I'm using play framework 2.4.2
with Java and I want to validate that a user is logged in by intercepting all requests and checking if a session value is set. So I have extended the DefaultHttpRequestHandler and overridden the createAction
Method to intercept all requests. However, I have not found a good way to validate the session.
When I try to fetch the session value I get a runtime exception: There is no HTTP Context available from here
Below is the class I'm working with:
public class RequestHandler extends DefaultHttpRequestHandler {
@Override
public Action createAction(Http.Request request, Method method) {
session("loggedIn"); // Throws runtime Exception: no HTTP Context
}
}
Since the session is technically a cookie I can retrieve the value from the header with code like the following:
for(String cookie : request.headers().get("Cookie")){
System.out.println("cookie: "+cookie);
}
But then I have to parse the cookie string which looks like the following line to get the loggedIn value. To dirty for my taste.
_ga=GA1.1.1508004144.1421266376; ki_r=; ki_t=1438789543788%378129908%3B1438789543788%3B1%3B1; PLAY_SESSION=0570411c3eb55ad230681539ddcfaa4220583fd-loggedIn=1
I notice some websites document a different approach and instead create an
action composition and add the appropriate annotation to every controller class or method.
The problem with this approach is it requires the developer to remember to add the annotation. I would prefer to reverse this to block every route by default and then add an annotation to the routes that do not need the validation.
A couple sites that document action composition:
Is there a way to globally validate if a user should have access to a page and how do I get at the session variable?
*Please note that I'm not interested in using a third party plugin for authentication.
Even if I would re-consider using action composition, you can fix Option 1.
Create a custom annotation to mark the actions that don't need validation.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoAuthRequired {}
Then change your HttpRequestHandler implementation.
public class RequestHandler extends DefaultHttpRequestHandler {
@Override
public Action createAction(Http.Request request, Method actionMethod) {
return new Action.Simple() {
@Override
public F.Promise<Result> call(Http.Context ctx) throws Throwable {
// if the action is annotated with @NoAuthRequired or user is logged in delegate to it
if (actionMethod.isAnnotationPresent(NoAuthRequired.class) || ctx.session().containsKey("loggedIn")) {
return delegate.call(ctx);
}
// otherwise, block access
else {
return F.Promise.pure(forbidden("You're not allowed"));
}
}
};
}
}
In this way, every route requires validation unless explicitly annotated.
As you can see from the code, the session is available through the Context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With