How to write a request handler for users accessing a generated document from the /file?guid= URL?

0
Hi all I have an app that generates a confirmation document when the user’s journey is complete, which they can access on their last page by clicking a download button. This button uses the Download file action, with the option “Show file in browser”, so it’s consistent with functionality on their other website. Problem is, this exposes a URL directly to the generated file, that the user could copy+paste, or bookmark. The document is restricted to current user, so if this URL is accessed later, or from another browser etc. they get a  401 error. This is good – we block the user from seeing documents that they didn’t create and don’t own. However, the file document 401 message is just the browser’s default 401, and isn’t very user friendly. So, enough context – I would like to use a custom request handler to catch a user as they access a file from the default “/file?guid...” URL. From there, I’d like to check if they have permission to view the document with that GUID. If they do not, I want to redirect them to a custom error page in my app. https://www.mendix.com/blog/requesthandlers-at-your-service/ I’ve followed this guide, and managed to set up the basic “Hello world” request handler, but am having trouble expanding that. I get errors when I change the “hello/” to “file?”, and am not familiar enough with request handlers yet to know why this might be failing. Does anyone have any experience with catching file requests, and handling them in a user friendly way? If you can think of any other non-request handling ways, that works too! Cheers
asked
1 answers
1

I’ve done something similar to add images into emails without having to embed them as base64. 

You can use a request handler to build the same function as “url/file?guid” but without the need for a user to be authenticated. 

Here is my java action code:

instead of “url/file?guid” im using “url/image?guid”. 

The IMXRuntimeResponse has an output stream that you can use to return the image. I used apache commons to easily copy an input stream to an output stream but that can be replaced if you dont want a dependency. 
 

import com.mendix.core.Core;
import com.mendix.externalinterface.connector.RequestHandler;
import com.mendix.m2ee.api.IMxRuntimeRequest;
import com.mendix.m2ee.api.IMxRuntimeResponse;
import com.mendix.systemwideinterfaces.core.IContext;
import com.mendix.systemwideinterfaces.core.IMendixIdentifier;
import com.mendix.systemwideinterfaces.core.IMendixObject;
import com.mendix.webui.CustomJavaAction;
import org.apache.commons.io.IOUtils;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import static com.mendix.core.Core.retrieveId;
import static com.mendix.core.Core.retrieveXPathQuery;

public class HostImages extends CustomJavaAction<java.lang.Boolean>
{
	public HostImages(IContext context)
	{
		super(context);
	}

	@java.lang.Override
	public java.lang.Boolean executeAction() throws Exception
	{
		// BEGIN USER CODE
		//throw new com.mendix.systemwideinterfaces.MendixRuntimeException("Java action was not implemented");



		try {

			Core.addRequestHandler("image", new handler());
			Core.getLogger("RequestHandlers").info("Image hosting initialized");

			return true;

		} catch(Exception e) {

			Core.getLogger("RequestHandlers").error("Image Hosting failed to initialize");

			return false;
		}




		// END USER CODE
	}

	/**
	 * Returns a string representation of this action
	 */
	@java.lang.Override
	public java.lang.String toString()
	{
		return "HostImages";
	}

	// BEGIN EXTRA CODE

	class handler extends RequestHandler {


		@Override
		public void processRequest(IMxRuntimeRequest request,
								   IMxRuntimeResponse response, String arg2) throws Exception
		{
			
			String guid = request.getParameter("guid");

			try {
				Core.getLogger("RequestHandlers").debug("guid found: " + guid);
				java.util.List<IMendixObject> result = retrieveXPathQuery(getContext(), "//MiCorr.Image[id='" + guid + "']");
				IMendixObject obj = result.get(0);

				OutputStream os = response.getOutputStream();
				InputStream is = Core.getFileDocumentContent(getContext(), obj);
				IOUtils.copy(is, os);
				IOUtils.closeQuietly(os);
				
				response.setStatus(IMxRuntimeResponse.OK);
				response.setContentType("image/png");

			} catch (Exception e) {

				response.setStatus(IMxRuntimeResponse.OK);

			}


		}



	}


	// END EXTRA CODE
}

 

answered