Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC interceptor vs Spring security filter vs something else...?

I'm using Spring-MVC with Spring Security for my web application. It includes user registration pages and private user panel. I have it set up currently with the following URL patterns:

  • whatever/myapp/login user log in
  • whatever/myapp/register?step=1 start registration
  • whatever/myapp/account/** private area views (pages)
  • whatever/myapp/pending view shown while post-registration processes complete
  • whatever/myapp/blocked account blocked view
  • whatever/myapp/register/retry if registration failed, allow retry

Essentially, these URLs below should require user authentication, i.e. require log-in:

  • whatever/myapp/account/** (private area pages)
  • whatever/myapp/pending (this page has a timer set to redirect to /account/home)
  • whatever/myapp/register/retry

This is quite straightforward to achieve using Spring security. However, regardless of user authentication through Spring security, private area pages should be accessible or not, depending on user's current account status (stored in my DB).

More specifically: if a user tries to access anything in the private area (/account/**), he should be shown the appropriate view (redirected to appropriate page), according to the status. I have these statuses defined:

  • suspended - relates to pending view
  • enabled - allow full access
  • disabled - not relevant here
  • retry_allowed- relates to retry view
  • blocked - relates to account-blocked view

Currently, I have a MVC interceptor setup to /account/**, that checks user status, and redirects to appropriate pages, but somehow I get the sense that this is not really the ideal or appropriate solution here, since I'm facing strange behavior, like multiple controller invocation... and also I'm not quite certain when to return true / false within preHandle() method. Here's the code snippet from the interceptor:

@Override
public boolean preHandle(
    HttpServletRequest request, 
    HttpServletResponse response,
    Object arg2) 
    throws Exception {

IPanelUser pUser =  (IPanelUser) SecurityContextHolder.getContext()
        .getAuthentication().getPrincipal();

// check principal first and then load from DB
// "suspended" is initial status upon registration
if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {

    // if suspended, load from DB and update status
    Customer customer = this.customerService.getUserByUsername(pUser.getUsername());
    if(customer != null)
        pUser.getCustomer().setStatus(customer.getStatus());

    // still suspended? redirect to pending
    if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {
        response.sendRedirect("../pending");
        return false;
    }
}

if(pUser.getCustomer().getStatus() == CustomerStatus.Blocked.getCode()) {

    // redirect to blocked page
    response.sendRedirect("../blocked");
    SecurityContextHolder.clearContext();
    return false;
}

if(pUser.getCustomer().getStatus() == CustomerStatus.AllowRetry.getCode()) {

    // redirect to CC submission page
    response.sendRedirect("../register/retry");
    return false;
}

if(pUser.getCustomer().getStatus() == CustomerStatus.Enabled.getCode() ||
   pUser.getCustomer().getStatus() == CustomerStatus.Disabled.getCode()) {

    // do nothing
}

return true;
}

.

Is this a valid approach ? Any alternative suggestions ?

like image 601
Less Avatar asked Oct 10 '13 09:10

Less


People also ask

What is the difference between filter and interceptor in Spring?

Filters can modify inbound and outbound requests and responses including modification of headers, entity and other request/response parameters. Interceptors are used primarily for modification of entity input and output streams. You can use interceptors for example to zip and unzip output and input entity streams.

Which one is called first filter or interceptor?

Interceptors will only execute after Filters. Fine-grained pre-processing tasks are suitable for HandlerInterceptors (authorization checks, etc.)

What is the difference between postHandle () and afterCompletion ()?

postHandle() : After a request is handled by a request handler. It gives access to the returned ModelAndView object, so you can manipulate the model attributes in it. afterCompletion() : After the completion of all request processing i.e. after the view has been rendered.

What are soring and filters?

Advertisements. A filter is an object used to intercept the HTTP requests and responses of your application. By using filter, we can perform two operations at two instances − Before sending the request to the controller.


1 Answers

All options are valid, it depends on the level of abstraction you want.

In a Filter, you only have access to HttpServletRequest and HttpServletResponse objects, so you are very much coupled with the Servlet API. You also don't (directly) have access to all the great Spring functionality like returning a view to be rendered or a ResponseEntity.

In a HandlerInterceptor, it's again more of the same. You can do your redirection or request handling directly in the preHandle() where you don't have access to the ModelAndView or set a flag which you check in postHandle(). You would have access to the ModelAndView but not to some other Spring MVC functionality.

Spring Security is a good alternative, but I find it has a lot of configuration that I don't like too much.

One final alternative, that I like the most, is to use AOP (you can do this with Spring Security or Shiro as well). You create an annotation like @Private and you annotate your @Controller handler methods. You use AOP to advise these methods. The advice basically checks some session or request attribute for a flag (authorized or not). If you are allowed, you continue executing the handler method, if not, you throw an UnauthorizedException (or similar). You then also declare an @ExceptionHandler for that exception where you have pretty much complete control over how the response is generated: a ModelAndView (and related), a ResponseEntity, annotate the handler with @ResponseBody, write the response directly, etc. I feel like you have much more control, if you want it.

like image 65
Sotirios Delimanolis Avatar answered Nov 04 '22 08:11

Sotirios Delimanolis