Most web applications use an authorization system to make sure the user is logged in and authorized to execute specific procedures. For example, a simple user will only have read access, while an admin can edit and delete. For every server endpoint, we ask ourselves : "Who has the privilege to access that service ?"
Implementing such a system is deceptively simple using Guice AOP once you have installed Guice Servlet to enable injection of servlet related objects, like HttpSession.
First, we need to create the annotation :
Then we implement the method interceptor :
Obviously, to get the logged in user you need the session. Thanks to Guice Servlet magic, you can inject a session provider in any object.
Finally, we bind the interceptor in the Guice ServletModule :
Don't forget that only objects instantiated by Guice will have their methods intercepted.
For such cross-cutting concerns, we are told that AOP is the key. Intercepting the methods we want to secure and checking authorization levels in a separate security aspect...
One thing that bothers me with such an approach is that when I want to check the access level of a method, I have to go look in the security aspect to see how it was intercepted. I'd rather have a declarative way to explicit the access level of a method, like an annotation :
@AuthorizationRequired(Role.ADMIN)
public void securedMethod() {}
Implementing such a system is deceptively simple using Guice AOP once you have installed Guice Servlet to enable injection of servlet related objects, like HttpSession.
First, we need to create the annotation :
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorizationRequired{
Role value();
}
Then we implement the method interceptor :
public class AuthorizationInterceptor implements MethodInterceptor {
@Inject private Provider<HttpSession> sessionProvider;
@Override
public Object invoke(MethodInvocation invoc) throws Throwable {
Role required = invoc.getMethod().getAnnotation(AuthorizationRequired.class).value();
User user = getUserFromSession(sessionProvider.get());
if (isUserAuthorized(user, required))
return invoc.proceed();
else
throw new UnauthorizedException("User is not authorized");
}
}
Obviously, to get the logged in user you need the session. Thanks to Guice Servlet magic, you can inject a session provider in any object.
Finally, we bind the interceptor in the Guice ServletModule :
AuthorizationInterceptor interceptor = new AuthorizationInterceptor (); requestInjection(interceptor); bindInterceptor(classMatcher, annotatedWith(AuthorizationRequired.class), interceptor );
Don't forget that only objects instantiated by Guice will have their methods intercepted.