Our login page needs to contain a form, which will of course, hold an email address (username) and password.

Play provides a forms API for handling the rendering, decoding and validation of forms. Let’s start off by implementing our form as a Java object. Open the app/controllers/Application.java class, and declare a static inner class called Login at the end of it:

The important thing to notice here is the @helper.form call. We have passed to it a route, routes.Application.authenticate. This tells Play where this form should be submitted to. Notice that there are no hard coded URLs here? This means we can change our URL structure without silently breaking our application.

Play actually offers a much richer set of form tags, but they are overkill for our login form. We will look at those later in the tutorial.

Of course, the authenticate route hasn’t been implemented yet, so let’s implement it now. First of all, add the route to conf/routes:

Currently, our authenticate action is doing nothing but reading our form. The next thing we want to do is validate the form, and there is only one thing we are concerned with in the validation, is the username and password correct? To implement this validation, we are going to write a validate method on the Login class in app/controllers/Application.java.

As you can see, this method is able to do any arbitrary validation, in our case, using the User.authenticate method that we’ve already implemented, and if validation fails, it returns a String with the error message, otherwise null if validation passes.

We can now use this validation by using the hasErrors() method on our Form object in the authenticate action:

This code introduces a number of new concepts. Firstly, if validation fails, we return a status of 400 Bad Request, rendering the login page with our form that had the failed validation. By passing this form back, we can extract any validation errors from the form, and the values the user entered, and render them back to the user.

If the validation was successful, then we put an attribute into the session. We call this attribute email, and it’s value is the email address of the user that just successfully logged in. We will use this session attribute later to find out the currently logged in user.

After setting the user in the session, we issue an HTTP redirect to the dashboard. You can see that we’ve used the reverse router, in the same way that we include assets in templates, to refer to the dashboard action.

We are almost finished with validation. The one thing left to do is to display the error message when validation fails. You saw before that we passed the invalid form back to the template, we will use this to get the error message. Place the following code in app/views/login.scala.html, just below the Sign In heading:

Now is a good time for us to start writing tests for our actions. We’ve written an action that provides the ability to log in, let’s check that it works. Start by creating a skeleton test class called test/controllers/LoginTest.java:

Notice that this time we’ve passed a fakeGlobal() to the fake application when we set it up. In fact, since creating our “real” Global.java, the ModelsTest we wrote earlier has been broken because it is loading the initial data when the test starts. So it too should be updated to use fakeGlobal().

Now let’s write a test that tests what happens when we authenticate successfully:

There are a few new concepts introduced here. The first is the user of Plays “ref” reverse router. This allows us to get a reference to an action, which we then pass to callAction to invoke. In our case, we’ve got a reference to the Application.authenticate action.

We are also creating a fake request. We are giving this a form body with the email and password to authenticate with.

Finally, we are using the status and session helper methods to get the status and the session of the result. We ensure that the successful login occurred with Bob’s email address being added to the session. There are other helper methods available to get access to other parts of the result, such as the headers and the body. You might wonder why we can’t just directly get the result. The reason for this is that the result may, for example, be asynchronous, and so Play needs to unwrap it if necessary in order to access it.

Run the test to make sure it passes. Now let’s write another test, this time to ensure that if an invalid email and password are supplied, that we don’t get logged in.

Now that we are able to login, we can start protecting actions with authentication. Play allows us to do this using action composition. Action composition is the ability to compose multiple actions together in a chain. Each action can do something to the request before delegating to the next action, and can also modify the result. An action can also decide not to pass the request onto the next action, and instead generate the result itself.

Play already comes with a built in authenticator action, which we will extend to add our logic. We will call this authenticator Secured. Open app/controllers/Secured.java, and implement this class.

We have implemented two methods here. getUsername is used to get the username of the current logged in user. In our case this is the email address, that we set in the email attribute in the session when the user logged in. If this method returns a value, then the authenticator considers the user to be logged in, and lets the request proceed. If however the method returns null, then the authenticator will block the request, and instead invoke onUnathorized, which we have implemented to redirect to our login screen.

Now let’s use this authenticator on the dashboard. In app/controllers/Application.java, add the @Security.Authenticated annotation with our authenticator to the index method:

Now try and visit the dashboard in a web browser. If you logged in successfully before, you’re probably now on the dashboard, the authenticator hasn’t blocked you because you were already logged in. You could close your browser and reopen it to log out, but now is as good a time as any for us to implement a log out action. As always, start with the route:

You can see we have cleared the session, this will log the user out. There is one new concept here. After clearing the session, we added an attribute to the flash scope, a success message. The flash scope is similar to the session, except that the flash scope lasts only until the next request comes in. This will allow us to render the success message in the login template when the redirected request comes in. Let’s add the message to app/views/login.scala.html, just as we did for the error message:

Now go to the dashboard in your browser, try logging out, and then visiting the dashboard again. You should be unable to view the dashboard, it will redirect to the login screen. Login, and you should be able to see the dashboard again.

There is one last thing that we want to do. We can currently block access to an action based on whether we are logged in, but how can we access the currently logged in user? The answer is through the request.username() method. This will give us the email address of the current user.

Let’s put the name of the user in the main template next to the logout link. To get the name, we’ll actually have to load the whole user from the database. Let’s also limit the projects to the one that the user is a member of, and the tasks to the ones that the user is assigned to, using the methods that we’ve already implemented on our models:

Start by loading the user in the index method in app/controllers/Application.java: