cult3

Registration and Authentication in Laravel 4

Sep 09, 2013

Table of contents:

  1. Registering new Users
  2. Authenticating existing Users
  3. Conclusion

Registration and Authentication are two of the most essential elements of a web application. Virtually every kind of web application uses the concept of authentication, and so it’s important to get it down correctly from the outset.

Fortunately, Laravel 4 makes it incredibly easy to set up a web application to register and authenticate users. As I’ve mentioned in previous tutorials, Laravel 4 ships with a number of features already set up for you.

In this tutorial I’m going to go over setting up the basic elements of registration and authenticating users in your web application.

Registering new Users

So if you have been following along with the “Building Cribbb” series, I’ve already built a method for creating new records on the User resource. However, because User’s aren’t a typical type of resource in this application, I’m going to move that method to a RegisterController.php file.

Register Controller

So the first thing we need to do is to create the Register Controller file and copy the following code:

use Cribbb\Storage\User\UserRepository as User;

class RegisterController extends BaseController
{
    /**
     * User Repository
     */
    protected $user;

    /**
     * Inject the User Repository
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function index()
    {
        return View::make("register.index");
    }

    public function store()
    {
        $s = $this->user->create(Input::all());

        if ($s->isSaved()) {
            return Redirect::route("users.index")->with(
                "flash",
                "The new user has been created"
            );
        }

        return Redirect::route("register.index")
            ->withInput()
            ->withErrors($s->errors());
    }
}

Hopefully if you have been following along with the series this code should look pretty familiar by now. If not, take a look through the previous tutorials at the bottom of this post.

So I’m basically just injecting an instance of the User Repository. For this Controller, we only need to be able to display the form and accept a POST. In this example I’m using the index() method to display the form and the store() method to accept the POST, but you can use whatever you want.

Register View

Next I will create a View to display the sign up form. Create a new file under app/views/register called index.blade.php and copy the following code:

@if ($errors->any())
<ul>
{{ implode("", $errors->all('<li>:message</li>'))}}
</ul>
@endif

{{ Form::open(array('route' => 'register.store')) }}

<p>{{ Form::label('username', 'Username') }}
{{ Form::text('username') }}</p>

<p>{{ Form::label('email', 'Email') }}
{{ Form::text('email') }}</p>

<p>{{ Form::label('password', 'Password') }}
{{ Form::text('password') }}</p>

<p>{{ Form::label('password_confirmation', 'Password confirm') }}
{{ Form::text('password_confirmation') }}</p>

<p>{{ Form::submit('Submit') }}</p>

{{ Form::close() }}

Again, if you have been following along with this series this code should look very familiar. Notice how I’ve set the route to register.store. If you are using a different Controller or a different method make sure you update this accordingly.

Register Routes

Next I need to define some routes so that we can hit the Controller in the browser:

Route::get("register", [
    "uses" => "RegisterController@index",
    "as" => "register.index",
]);
Route::post("register", [
    "uses" => "RegisterController@store",
    "as" => "register.store",
]);

For the Register Controller we only need a GET route to display the form and a POST route to accept the submitted form. As you can see from the code above, all I’m doing here is defining the route, pointing it to the correct Controller and method and assigning it an alias.

Register tests

And finally we can write a couple of tests to ensure everything is working as it should:

class RegisterController extends TestCase
{
    /**
     * Test Index
     */
    public function testIndex()
    {
        $this->call("GET", "register");

        $this->assertResponseOk();
    }

    /**
     * Test Store fails
     */
    public function testStoreFails()
    {
        $this->mock
            ->shouldReceive("create")
            ->once()
            ->andReturn(Mockery::mock(["isSaved" => false, "errors" => []]));

        $this->call("POST", "register");

        $this->assertRedirectedToRoute("register.index");
        $this->assertSessionHasErrors();
    }

    /**
     * Test Store success
     */
    public function testStoreSuccess()
    {
        $this->mock
            ->shouldReceive("create")
            ->once()
            ->andReturn(Mockery::mock(["isSaved" => true]));

        $this->call("POST", "register");

        $this->assertRedirectedToRoute("users.index");
        $this->assertSessionHas("flash");
    }
}

Once again, if you have been following along, all three of these tests should already be familiar. If not, take a look back at the previous tutorials for a more in-depth explanation into how each of them work.

Authenticating existing Users

Next we need to authenticate users when they attempt to log in. This is fairly similar to the process of registering a new User and so there shouldn’t be too much new to learn here.

Authentication Controller

One thing to note is, I usually name my “login” Controller SessionController.php because we are either creating or destroying a Session. Again, it doesn’t really make a difference as to what you call it, so feel free to name it whatever you want.

So the first thing we will do is to create SessionController.php:

use Cribbb\Storage\User\UserRepository as User;

class SessionController extends BaseController
{
    /**
     * User Repository
     */
    protected $user;

    /**
     * Inject the User Repository
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Show the form for creating a new Session
     */
    public function create()
    {
        return View::make("session.create");
    }

    public function store()
    {
        if (
            Auth::attempt([
                "email" => Input::get("email"),
                "password" => Input::get("password"),
            ])
        ) {
            return Redirect::intended("/");
        }
        return Redirect::route("session.create")
            ->withInput()
            ->with("login_errors", true);
    }

    public function destroy()
    {
        Auth::logout();

        return View::make("session.destroy");
    }
}

So first I inject an instance of the User Repository into the construct method. Next I use the create method to display the form, the store method to accept the POST and create a new Session and the destroy method to destroy the Session and log the user out.

Notice the Auth::attempt() and the Auth::logout() methods? Laravel already provides you with these methods to make authentication much easier and to save you reinventing the wheel.

Another interesting thing to note is:

Redirect::intended("/");

This will automatically redirect the User to the restricted page they were trying to view, or it will default to the URL your provide. In this instance I just want to default to the root. This is another nice Laravel 4 touch because it is so annoying when you are forced to log in to a site to see a certain page, but once you are logged in you are automatically redirected to the default page. With Laravel 4, this will work out of the box.

Authentication Views

Next I will create the two views that I’m going to need to display the login form and the confirmation message when a User has signed out.

Under app/views/session create create.blade.php and destroy.blade.php and copy the following code.

Create:

@if (Session::has('login_errors'))
<span class="error">Username or password incorrect.</span>
@endif

{{ Form::open(array('route' => 'session.store')) }}

<p>{{ Form::label('email', 'Email') }}
{{ Form::text('email') }}</p>

<p>{{ Form::label('password', 'Password') }}
{{ Form::password('password') }}</p>

<p>{{ Form::submit('Submit') }}</p>

{{ Form::close() }}

Destroy:

You have successfully logged out

Authentication Routes

In order to be able to access the authentication through the browser, we need to set up a couple of routes:

Route::get("login", [
    "uses" => "SessionController@create",
    "as" => "session.create",
]);
Route::post("login", [
    "uses" => "SessionController@store",
    "as" => "session.store",
]);
Route::get("logout", [
    "uses" => "SessionController@destroy",
    "as" => "session.destroy",
]);

Again pretty similar to the Register routes, I simply need to GET the login form and POST to the store method. You will also notice that I have set up the logout route to simply GET the destroy method. In the future I will change this to use the proper RESTful method of DELETE, but for now I just want an easy way to get rid of the session by hitting the route in a browser.

Authentication Tests

And finally we can write a couple of tests to ensure that our authentication is working correctly.

Check that the login view is loading correctly:

/**
 * Test Index
 */
public function testCreate()
{
    $this->call('GET', 'login');

    $this->assertResponseOk();
}

Test that the failed authentication flow is correct:

/**
 * Test Store failure
 */
public function testStoreFailure()
{
    Auth::shouldReceive('attempt')->andReturn(false);

    $this->call('POST', 'login');

    $this->assertRedirectedToRoute('session.create');
    $this->assertSessionHas('flash');
}

And finally that the successful authentication flow is working:

/**
 * Test Store success
 */
public function testStoreSuccess()
{
    Auth::shouldReceive('attempt')->andReturn(true);

    $this->call('POST', 'login');

    $this->assertRedirectedToRoute('home.index');
}

Conclusion

Laravel 4 also ships with a couple of other authentication features which I have not covered in this post. Instead I’ll take a deeper look at those features when I integrate them into Cribbb.

Now that we have got registering and authentication set up, next we need to be able to protect certain routes and actions so that only authenticated users may access them. To do that, we will use Laravel’s fantastic filter system.

Come back next week when I’ll be taking a deep dive on filters in Laravel 4!

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.