Laravel 5 New Auth Generators and User Authentication

Laravel 5 New Auth Generators and User Authentication

Laravel 5 New Auth Generators and User Authentication Screenshot

In my previous article, I had covered the new added features for validation in Laravel 5. Today, we will cover the new authentication facilities that are available in Laravel 5. With the inclusion of new Auth Generators, the whole process of setting up an authentication system has now become so much easier. For the demonstration purpose we will create a simple user login and registration system.

The Auth generator commands have been removed from the final release of Laravel 5 in favour of out of the box authentication.

The rest of the article is still valid and compatible with Laravel 5. If you are a beginner to Laravel 5, this article will help you in understanding how authentication in Laravel 5 works and can be implemented.

New Auth Generators

The CLI tool in Laravel 5, artisan now provides us with the four new generators for speeding up the authentication setup process:

  • auth:controller – generates an authentication controller with the necessary boiler-plate methods.
  • auth:login-request – generates a form request for validating a login request.
  • auth:register-request – generates a form request for validating a register request
  • make:auth – generates all the required classes for the authentication system.

 

Creating the Users Table

To store the user credentials, we will need a database table. So, let us go ahead and generate a migration class for the users table:

<?php
// generated using: ./artisan make:migration --create='users' create_users_table
// file : databases/xxxx_xx_xx_xxxxxx_create_users_table

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('email');            
            $table->string('password');
            $table->string('remember_token',100)->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('users');
    }

}

Please note that, artisan migrate:make command will not be available in Laravel 5. Use artisan make:migration command instead.

To run the migration we use artisan migrate command.

Generating the AuthController

Now, let us drop to the terminal and generate an AuthController and see what it looks like:

$ ./artisan auth:controller
Controller created successfully.
Route: Route::controller('auth', 'Auth\AuthController');

The above command will generate the following controller class inside the app/Http/Controllers/Auth directory :

Since the auth:controller command has been removed, you will need to create the following controller inside the app/Http/Controllers/Auth directory. Alternatively, you can also use the make:controller 'Auth\AuthController' command and fill the generated file with the following code . Oh, wait there is already an Auth\AuthController in Laravel 5 just replace its content with the following code:

<?php namespace App\Http\Controllers\Auth;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;

use App\Http\Requests\Auth\LoginRequest;
use App\Http\Requests\Auth\RegisterRequest;

class AuthController extends Controller {

    /**
     * the model instance
     * @var User
     */
    protected $user; 
    /**
     * The Guard implementation.
     *
     * @var Authenticator
     */
    protected $auth;

    /**
     * Create a new authentication controller instance.
     *
     * @param  Authenticator  $auth
     * @return void
     */
    public function __construct(Guard $auth, User $user)
    {
        $this->user = $user; 
        $this->auth = $auth;

        $this->middleware('guest', ['except' => ['getLogout']]); 
    }

    /**
     * Show the application registration form.
     *
     * @return Response
     */
    public function getRegister()
    {
        return view('auth.register');
    }

    /**
     * Handle a registration request for the application.
     *
     * @param  RegisterRequest  $request
     * @return Response
     */
    public function postRegister(RegisterRequest $request)
    {
        //code for registering a user goes here.
        $this->auth->login($this->user); 
        return redirect('/dash-board'); 
    }

    /**
     * Show the application login form.
     *
     * @return Response
     */
    public function getLogin()
    {
        return view('auth.login');
    }

    /**
     * Handle a login request to the application.
     *
     * @param  LoginRequest  $request
     * @return Response
     */
    public function postLogin(LoginRequest $request)
    {
        if ($this->auth->attempt($request->only('email', 'password')))
        {
            return redirect('/dash-board');
        }

        return redirect('/login')->withErrors([
            'email' => 'The credentials you entered did not match our records. Try again?',
        ]);
    }

    /**
     * Log the user out of the application.
     *
     * @return Response
     */
    public function getLogout()
    {
        $this->auth->logout();

        return redirect('/');
    }

}

 

A Note About Guard Contract: In Laravel 5, the IoC container can now resolve the instance of the Guard class associated with the current Auth Driver. You can verify this by running the following code on 5 and any previous version of Laravel 4:

var_dump(App::make('Illuminate\Auth\Guard'));

On a previous version say 4.2, you will get a Illuminate\Container\BindingResolutionException. So what has changed now? Well, if you take a look at the Illuminate\Foundation\Application.php you will find the following key values pair in the $aliases array of the registerCoreContainerAliases method:

'auth.driver'=>['Illuminate\Auth\Guard', 'Illuminate\Contracts\Auth\Guard'],

Also, the Illuminate\Auth\AuthServiceProvider.php now has an additional binding:

$this->app->singleton('auth.driver', function($app)
{
    return $app['auth']->driver();
});

In simpler words, this implies that both the Illuminate\Auth\Guard class and the Illuminate\Contracts\Guard contract / interface will be resolved to the same instance, which will essentially be a Guard instance.

Note
Please note the custom changes in the AuthController code.

Now, if we take a look at the constructor method of the AuthController, we can safely assume that we are going to have a Guard instance available to our AuthController in the form of the auth property. I have also added a User $user parameter in the constructor method so that we can manipulate a User record through the user property. The middleware method of Controller class allows us to define any middlewares that should be run before a controller action is dispatched. In this case, I have specified the guest middleware — avilable by default in Laravel 5. The guest middleware will prevent the user from re-login or register if he / she is already logged in. In the getLogout method, the logout method on the Guard instance is called to log out the user.

The postRegister method has a type hint RegisterRequest for the $request parameter. This will make sure that the data is validated before passed in to the postRegister method. ( See: Laravel 5 Form Validation). Same is true for the postLogin method except that the type hint is the LoginRequest.

Now to save a user upon registration, all we need is to add the following statements in the postRegister method:

$this->user->email = $request->email;
$this->user->password = bcrypt($request->password);
$this->user->save();

And our work is done here.

Generating the Form Requests

Now lets us generate both the RegisterRequest and LoginRequest classes by using the artisan auth:register-request command and the artisan auth:login-request command respectively:

$ ./artisan auth:register-request
Request created successfully.
$ ./artisan auth:login-request
Request created successfully.

The above commands will generate the following two FormRequest classes respectively in the app/Http/Requests/Auth directory:

Please use the make:request 'Auth\RegisterRequest' and make:request 'Auth\LoginRequest' artisan commands to create the RegisterRequest and LoginRequest classes respectively.

Now, the generated classes should be modified as follows:

<?php namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;

class RegisterRequest extends FormRequest {

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'email' => 'required|email|unique:users',
            'password' => 'required|confirmed|min:8',
        ];
    }

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

}
<?php namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;

class LoginRequest extends FormRequest {

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'email' => 'required', 'password' => 'required',
        ];
    }

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

}

Note the convenience here! Every thing has already been done for us — still true :).

The HomeController and the DashBoardController

Lets us create two more controllers, one for handling the home page and the other for handling the dashboard page.

The code for the app/Http/Controllers/DashBoardController.php :

<?php namespace App\Http\Controllers;

class DashBoardController extends Controller {

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Show the application dashboard to the user.
     *
     * @return Response
     */
    public function index()
    {
        return view('dashboard');
    }

}

In the constructor method of the Controller, I have applied the auth middleware to restrict the access to the controller actions. The auth middleware will redirect the non-authenticated users to the login page. Here is the code for the auth middleware which is available by default and is located at app/Http/Middleware directory:

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\Guard;

class Authenticate {

    /**
     * The Guard implementation.
     *
     * @var Guard
     */
    protected $auth;

    /**
     * Create a new filter instance.
     *
     * @param  Guard  $auth
     * @return void
     */
    public function __construct(Guard $auth)
    {
        $this->auth = $auth;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($this->auth->guest())
        {
            if ($request->ajax())
            {
                return response('Unauthorized.', 401);
            }
            else
            {
                return redirect()->guest('login');
            }
        }

        return $next($request);
    }

}

The HomeController is available by default. Just replace its content with the following code (remove the constructor function):

/**
 * Show the application home page to the user.
 *
 * @return Response
 */
public function index()
{
    return view('homepage');
}

Creating the Views

Installing the illuminate/html package
Use the following instructions to install the illuminate/html package:

  • Add the following lines in the require section of composer.json file and runt the composer update command.
    "illuminate/html": "~5.0"
  • After the completion of the installation process, register the service provider in config/app.php by adding the following value into the providers array:
    'Illuminate\Html\HtmlServiceProvider'
  • Now register facades by adding these two key value pairs in the aliases array:
    'Form'=> 'Illuminate\Html\FormFacade',
    'HTML'=> 'Illuminate\Html\HtmlFacade'

All of our views will be extending a master view so lets us first create the master layout (resources/views/master.blade.php):

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel 5 New Auth Generators and User Authentication</title>
    {!!HTML::style('assets/css/bootstrap.css')!!}
    {!!HTML::style('assets/css/style.css')!!}
</head>
<body>
    <div class="container">
    <header id="header">
        <div class="jumbotron">
            <h1>Laravel 5: New Auth Generators and User Authentication</h1>
        </div>
    </header>
        <div class="row">
            @yield('main')
        </div>
    </div>
</body>
</html>

The style method on the HTML facade is called to generate the links to the CSS resources. The contents of the child views will be injected inside the div element with the row class.

resources/views/homepage.blade.php:

<!-- -->
@extends('master')

@section('main')

<div class="container">
    <div class="row">
         <div class="col-md-12">
             <p>Use the following links to login / register:
                 {!!HTML::link('/login','Login',['class'=>'btn btn-link'])!!}/{!!HTML::link('/register','Register',['class'=>'btn btn-link'])!!}
             </p>
         </div>
    </div>
</div>

@stop

In our home page we are displaying the links to the /login and the /register routes. The link HTML helper allows us to generate the link for a specified path.

resources/views/dashboard.blade.php:

<!-- -->
@extends('master')

@section('main')

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <p>
                Welcome to the Dashboard, use {!!HTML::link('/logout','Logout',['class'=>'btn btn-link'])!!} to logout.
            </p>
       </div>
   </div>
</div>

@stop

The Login and Register Forms

resources/views/auth/login.blade.php:

<!-- -->
@extends('master')

@section('main')
    <div class="col-md-8 col-md-offset-2 form-content">
        <h3 class="heading">Login</h3>
        @foreach($errors->all() as $error)
            <p class="alert alert-danger">{!!$error!!}</p>
        @endforeach
        {!!Form::open(['url'=>'/login','class'=>'form form-horizontal','style'=>'margin-top:50px'])!!}
        <div class="form-group">
            {!! Form::label('email','Email:',['class'=>'col-sm-3 control-label']) !!}
            <div class="col-sm-8">
                {!! Form::text('email',Input::old('email'),['class'=>'form-control']) !!}
            </div>
        </div>
        <div class="form-group">
        {!! Form::label('password','Password:',['class'=>'col-sm-3 control-label']) !!}
            <div class="col-sm-8">
                {!! Form::password('password',['class'=>'form-control']) !!}
            </div>
        </div>
        <div class="text-center">
            {!!Form::submit('Login',['class'=>'btn btn-default'])!!}
        </div>
        {!!Form::close()!!}
    </div>
 
@stop

In the above code, The @foreach blade directive is used to loop through the validation errors (if any) that are passed to the login view from the controller action. The open form helper is used to create a form open tag with action as /login, the method is assumed as POST by default. Next, the two input fields are created using the text and password helpers along with their respective labels. Finally, a submit button is generated and the form is closed.

resources/views/register.blade.php:

<!-- -->
@extends('master')

@section('main')
    <div class="col-md-8 col-md-offset-2 form-content">
        <h3 class="heading">Register</h3>
        @foreach($errors->all() as $error)
            <p class="alert alert-danger">{!!$error!!}</p>
        @endforeach
        {!!Form::open(['url'=>'/register','class'=>'form form-horizontal','style'=>'margin-top:50px'])!!}
        <div class="form-group">
            {!! Form::label('email','Email:',['class'=>'col-sm-3 control-label']) !!}
            <div class="col-sm-8">
                {!! Form::text('email',Input::old('email'),['class'=>'form-control']) !!}
            </div>
        </div>
        <div class="form-group">
            {!! Form::label('password','Password:',['class'=>'col-sm-3 control-label']) !!}
            <div class="col-sm-8">
                {!! Form::password('password',['class'=>'form-control']) !!}
            </div>
        </div>
        <div class="form-group">
            {!! Form::label('password_confirmation','Confirm Password:',['class'=>'col-sm-3 control-label']) !!}
            <div class="col-sm-8">
                {!! Form::password('password_confirmation',['class'=>'form-control']) !!}
            </div>
        </div>
        <div class="text-center">
            {!!Form::submit('Register',['class'=>'btn btn-default'])!!}
        </div>
        {!!Form::close()!!}
    </div>
 
@stop

Creating Routes

Our work is almost done. As a final step, we need to map the request paths to the appropriate controller methods. The routing API of Laravel allows us to intercept any type of request ( GET, POST, PUT, DELETE ) and send it to the suitable controller action.

In Laravel 5, we use the app/Http/routes.php file to define the application routes. The following code needs to be replaced with the default content of the routes.php file:

Route::get('/',['as'=>'home','uses'=>'HomeController@index']);
Route::get('/dash-board',['as'=>'dash-board','uses'=>"DashBoardController@index"]);

Route::controller('/','Auth\AuthController');

The first route defines that, a GET request with a path ‘/’ should be handled by the index method of the HomeController. Similary, the ‘/dash-board’ path is mapped to the index method of the DashBoardController.

On the last line, the controller method is used to generate the routes for the Auth\AuthController. Please refer to the documentation for the further details on the controller method.


15 thoughts on “Laravel 5 New Auth Generators and User Authentication

  1. Pavel Zotov Reply

    What about continue?

    1. Usman Riaz author Reply

      I will continue it soon, just waiting for Laravel 5 to reach its beta state at least, or become a bit more stable.

      Thanks.

  2. jasper Reply

    It appears that the Auth Generators you talk about in this article don’t exist in the current 5.0.4

    1. Usman Riaz author Reply

      Thank you for pointing that out. I have updated the article. Please let me know if something is still missing.

  3. Christian Bertaud Reply

    Very good article, very usefull.
    Works fine. Thank you very much :
    Just one point for the path of the register view :
    resources/views/auth/register.blade.php an not resources/views/register.blade.php (/auth is missing)

  4. Micael Reply

    Hi,

    I tried to do this and I got it all done, running on a localhost, I’ve customised it with bootstrap but now whenever I try to register I get this:

    at Controller->missingMethod(‘auth/login’)
    at call_user_func_array(array(object(AuthController), ‘missingMethod’), array(‘_missing’ => ‘auth/login’)) in Controller.php line 246
    at Controller->callAction(‘missingMethod’, array(‘_missing’ => ‘auth/login’)) in ControllerDispatcher.php line 162
    at ControllerDispatcher->call(object(AuthController), object(Route), ‘missingMethod’) in ControllerDispatcher.php line 107

    Do you have any idea on what is missing?
    Thanks for the tut!

    1. Usman Riaz author Reply

      What does the exception say? can you share your route specifications?

      1. Micael Reply

        I’m quite a lamer trying to learn. So I didn’t find anything like the error I was getting on the browser so I checked the log (after one full day on this… ) and it seems it was something with bootstrap.

        I had to add this on the /bootstrap/app.php :
        $app->singleton(
        ‘Illuminate\Contracts\Debug\ExceptionHandler’,
        ‘App\Exceptions\ExceptionHandler’
        ‘App\Exceptions\Handler’
        );

        ::::::

        Now it doesn’t give me the error, but instead redirects me to login and doesn’t register any variable on the mysql database.

        Thanks Usman. I’m using Laravel 5, with homestead. It did create the table when I did the migrate, so the mysql connection should be fine. I added a couple of fields to the form I don’t know if that can be the error?

        For instance I added First & Last name as input fields and labeled them accordingly (I think LOL).

        I think maybe I should learn all of it by scratch in order to know what is going wrong…

        1. Usman Riaz author Reply

          Ok, I just reproduced your error by specifying the wrong path in HTML::link for example changing the HTML::link('/login',..) to HTML::link('auth/login',..) produces the same error, please check your view files and hunt it down. It will solve the issue.

        2. Usman Riaz author Reply

          As an alternative you can change the path inside the routes.php:
          Route::controller('auth', 'Auth\AuthController').

          Usman.

          1. Micael

            Thanks for the heads up!

            In the end I opted to do a clean install and will try to learn the Authenticate routines from scratch. IF you know any good resource where I could learn let me know. It’s to use mysql, creating a table for users and each user has their own password.

            Thanks

          2. Usman Riaz author

            You are welcome, I would suggest subscribing to Laracasts, Jeffrey Way is by far the best PHP/Laravel teacher. Also the forum is very active. And keep visiting 🙂 time to time, you will find some useful articles here as well in comming week or so.

            Usman.

  5. Rakesh Reply

    I am getting following error.

    ErrorException in EloquentUserProvider.php line 106:
    Argument 1 passed to Illuminate\Auth\EloquentUserProvider::validateCredentials() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\user given, called in \vendor\laravel\framework\src\Illuminate\Auth\Guard.php on line 383 and defined

    1. Usman Riaz author Reply

      Rakesh, can you show me your App\User class?

    2. Joel Reply

      Rakesh,
      Ensure that your user class extends AuthenticatableContract

      class User extends Model implements AuthenticatableContract {

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Time limit is exhausted. Please reload CAPTCHA.