Announcement Announcement Module
Collapse
No announcement yet.
Accessing Services in the view Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Accessing Services in the view

    Hi all,

    I have a question about accessing services in the view-layer. We're building an application where we have the principals (users and "groups") modeled as a graph, where the arcs in the graph represents a relation to an other principal. Until now we have setup our model for the view so that the view get all it needs from the controller, but this requires quiet a bit of extra code, both in the formbeans and the controller code. We have been discussing writing a taglib/function that does this lookup for us but some of my co workers thinks it's a bad idea accessing the Services, and thereby the database in the view. My gut feeling say it's wrong but I can't really see any better solution. So my question, is it nessecarily an evil thing accessing the services/db through a taglib in the view?

    Thanks in advance
    Robert Lerner

  • #2
    Something for AOP?

    Hi Rob,

    You could try posting this on theserverside.com and see how long the thread gets... my guess is around 70 posts

    Have you considered using AOP to set up the users and groups? Users/groups sounds like a cross-cutting concern and as such suitable for AOP.

    Cheers

    Mike

    Comment


    • #3
      Nothing for AOP (in my understanding)

      Hi Mike, thanks for your reply.

      I've thought about solving this with AOP but I came to the conclusion that this isn't a crosscutting concern. What I like to do is, for instance, ask if the current principal has a relation X to principal Y, where Y can be an owner of an entity. Which relation X represents differs in the views and I'm not keen on reading all types of relations and introducing them on the principal object since that would read lots of information that I don't need in all views. In our model it's possible for a principal to have a 'mentor' relation to one principal, an 'admin' relation to an other principal and so forth. Depending on the context the current principal has different roles.

      One example: Listing a number of principals I'd like to be able to render a link to some admin action for each principal that the current principal has an admin relation to but I'm not interested in the rest of the relations.

      /Robert

      Comment


      • #4
        Abstract the authorisation from the view to the controller?

        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

        Comment

        Working...
        X