I've done something similar in the web-app I'm working on at the moment. Say, for example, you're viewing a person's details in a web-page, the app needs to determine whether to render an "edit details" button. It needs to render this if the current user is a manager or the owner of the details.
I've added a method to the controller that is responsible for editing the details (eg: EditUserDetailsController) called authorizeInvoke(...), which is defined in an interface. A custom tag is used to query this controller to see whether (continuing the example) the current user would be allowed to execute the action and therefore whether to display the button, or in your case, render the link.
The controller code looks something like this:
Code:
package uk.co.mindfruit.coreweb.domain.logic;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.ModelAndViewDefiningException;
import org.springframework.web.servlet.mvc.SimpleFormController;
import uk.co.mindfruit.coreweb.util.UserUtils;
public abstract class NewAbstractAuthFormController extends SimpleFormController implements AuthorizedHandler {
protected String notAuthViewName = ".notAuthorized";
public NewAbstractAuthFormController() {
super();
}
/**
* @param request
* @param response
* @param form
* @param errors
* @return
* @throws Exception
* @see uk.co.mindfruit.coreweb.domain.logic.SecureFormController#secureOnSubmit(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.validation.BindException)
*/
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object form, BindException errors) throws Exception {
if (authorizeInvoke(request, response) || UserUtils.getAuthUser(request).isAdministrator()){
return handleAuthSubmit(request, response, form, errors);
}
else {
throw new ModelAndViewDefiningException(new ModelAndView(notAuthViewName));
}
}
/**
* I test whether the current user is permitted to view the form, redirecting to a
* "permission denied" page if necessary. I call {@link #authorizeInvoke(HttpServletRequest,
* HttpServletResponse)} before calling <code>super.showForm(...)</code>. Subclasses can
* override this method to provide more fine-grained authorization processing.
*
* @param request
* @param response
* @param errors
* @param controlModel
* @return
* @throws Exception
* @see org.springframework.web.servlet.mvc.SimpleFormController#showForm(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.validation.BindException, java.util.Map)
*/
protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException errors, Map controlModel) throws Exception {
if (authorizeInvoke(request, response) || UserUtils.getAuthUser(request).isAdministrator()){
return super.showForm(request, response, errors, controlModel);
}
else {
throw new ModelAndViewDefiningException(new ModelAndView(notAuthViewName));
}
}
/**
* @param request
* @param response
*/
public abstract boolean authorizeInvoke(HttpServletRequest request, HttpServletResponse response) throws Exception;
/**
* Implement the code required to carry out the processing required on a FORM submission.
* @param request
* @param response
* @param form
* @param errors
* @return
* @throws Exception
*/
protected abstract ModelAndView handleAuthSubmit(HttpServletRequest request, HttpServletResponse response, Object form, BindException errors) throws Exception;
//------------------------------------------------------------------------- Spring setters
public void setNotAuthViewName(String notAuthViewName) {
this.notAuthViewName = notAuthViewName;
}
}
The AuthorizedHander:
Code:
package uk.co.mindfruit.coreweb.domain.logic;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthorizedHandler {
public boolean authorizeInvoke(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
The tag is a bit more complicated and I'd be happier if you rolled your own! But basically, you're looking for something like this:
Code:
<mytag:checkAuth path="/user/editDetails.do" var="path">
<form path="${path}" method="post">
<input type="hidden" name="user.id" value="147"/>
<input type="submit" value="edit user"/>
</form>
</mytag:checkAuth>
The tag needs to lookup the WebApplicationContext and discover which controller is mapped to "/user/editDetails.do". I had to override SimpleUrlHandlerMapping to make the lookupHandler(String path) method visible.
It works really quite well (if I do say so myself) and keeps the code which determines whether widgets get displayed in the view within the controller which ultimately proceeses the relevant request. You can, of course, implement the same interface on "plain" controllers too, which requires a base class deriving from AbstractController.
Any use?
Cheers
Mike