javasessionauthenticationgwtrequestfactory

GWT RequestFactory-based authentication


I am experimenting with GWT RequestFactory (RF) for the first time and am trying to implement a simple sign-in screen and authentication system (not using anything fancy, just fiddling around with the basics here). The basic user experience I'm looking to achieve is pretty par for the course:

The user will be presented with a sign-in screen (email and password and "Sign In" button). When they click the button, I want to use RF to send their credentials to the server (using ValueProxy since these are not entities) and authenticate them. If the credentials were correct, they are now "signed in" to the system, and the GWT app will download a whole new module and they'll be redirected to their account's main menu. If the credentials were incorrect, I want to send back a String explaining that the email or password was incorrect, and they are still "signed out" of the app.

Regarding this question that I posted yesterday, I have now figured out how to use RF to expose a SignInOutService which has a signIn(SignIn) method for attempting to sign the user in, and a signOut(SignOut) method for signing the user out of the system. But now I'm actuallly trying to implement that service, and here's what I have so far:

public class DefaultSignInOutService {
    // Try to sign the user into the system.
    public String signIn(SignIn signIn) {
        // The SignIn object contains the email/hashed password the user tried
        // signing-in with, as well as other metadata I'm looking to store for
        // security purposes (IP address, user agent, etc.).
        String email = signIn.getEmail();
        String hashedPassword = signIn.getHashedPassword();

        // This will be set to a non-null value if the sign-in attempt fails.
        // Otherwise (on successful sign-in) it will stay NULL. The client-side
        // handler will know what to do with the UI based on this value.
        String failReason = null;

        // For this simple example, the password is "12345" and below is it's MD5 hash.
        // Hey! That's the combination on my luggage!
        if(!"skroob@spaceballs.example.com".equals(email) || !"827ccb0eea8a706c4c34a16891f84e7b".equals(hashedPassword))
            failReason = "Login failed; incorrect email or password.";
        else {
            // Log the user into the system...

            // TODO: How?
        }

        return failReason;
    }

    // Sign the user out of the system.
    public void signOut(SignOut signOut) {
        // The SignOut object should reference the user attempting to sign out, as well as a reason
        // for why the sign out is occurring: the user manually requested to be signed out, or they
        // "expired" due to inactivity or navigating the browser away from the app, and so the system
        // auto-signed them out, etc.

        // TODO: How?
        return;
    }
}

So now, I've implemented my super-simple email/password check, and I'm ready to write the code that somehow signs the user into the app (so that they're not presented with a login screen over and over again). And I'm choking on what to do next.

Issues I'm trying to find solutions for:

  1. Is GWT RF somehow session- or token-based? If so, under the commented line "Log the user into the system...", what code can I write that says "this user is now authenticated, set some cookie or session variable to make it so!"? I ask this because once they sign in and are routed to the new module and main menu, GWT will need a way to authenticate every subsequent RF request thereafter.
  2. What does the signOut() method need to reset/clear/nullify in order to clear these cookies/session vars? In other words, how do I actually sign the user out, so if they try to go to the URL for their main menu (which again is only accessible if they're signed in), they'll be redirected to the sign-in screen?
  3. How could I implement a 15-min inactivity timeout, where the user is automatically signed out of the app after a certain length of time? I think this answer will become more obvious once I see how questions #1 and #2 above work.

I was told that I may need to have two servlets and/or filters: one for handling unauthenticated RF requests (while a user is signed out or has not yet signed in), and one for handling authenticated RF requests (once the user is actively signed in). But I can't see how they fit into the overall picture here.


Solution

  • The easiest way is to store your authentication details in session.

    public String signIn(SignIn signIn) {
        ...
        if(!"skroob@spaceballs.example.com".equals(email) || !"827ccb0eea8a706c4c34a16891f84e7b".equals(hashedPassword))
            failReason = "Login failed; incorrect email or password.";
        else {
            RequestFactoryServlet.getThreadLocalRequest().getSession().setAttribute("auth", signIn);
        }
        return failReason;
    }
    
    public void signOut(SignOut signOut) {
        RequestFactoryServlet.getThreadLocalRequest().getSession().removeAttribute("auth");
        return;
    }
    

    On every request you can check if SignIn object is still present in session:

    SignIn signIn = null;
    final Object userObject = RequestFactoryServlet.getThreadLocalRequest().getSession().getAttribute("auth");
    if (userObject != null && userObject instanceof SignIn) {
      signIn = (SignIn) userObject;
    }
    

    In case of absence of this object you should cancel the request and redirect user to login page.