Back to blog

Multi Auth in Laravel 5.4, Chapter I : Registration

February 02, 2017

Chapter 1 :: Registration

Introduction

You have heard people talking about the awesome features of authentication guards in Laravel and how we can use them to authenticate multiple user providers / models. But do not know where to begin. Don’t worry, we will cover nearly every puzzle about session based MultiAuth (that’s what most people say) in 3 chapters.

Before proceeding with how to get things done, i strongly recommend to go through documentation of Authentication in laravel

Authentication in Laravel 5.4

TL;DR

If you are getting bored and do not have patience or will to follow the rest of chapter. Then you can refer the repository. Check the commit history for details.

Repository for Multi Auth in Laravel

Why do we need it

There are instances where we wanted to have a separate authentications logic for administrators apart from default user, some may argue that authorization/roles can accomplish this goal. But there are situations where we want to have different rules and relationships for user and administrator.

Chapter I :: Registration

In the first chapter, we will cover registration of our custom user whom we will call SELLER (don’t like to call it admin). We will not be using new features of laravel 5.4 like Markdown Mail & Notifications & Fluent Routing because we want this steps to work in Laravel 5.3 too. So, Let’s dig in.

You can install a fresh copy of Laravel or can use your existing project (must be in v5.4 or v5.3)

Now let’s run Laravel’s authentication scaffolding

php artisan make:auth

Well you might be wondering, this topic is about MultiAuth,why should we care about laravel’s default user. You are right, this step is entirely optional, you can skip it if you want.

Let's create a new model and migration for our custom user Seller.

php artisan make:model Seller -m

Open up the seller’s migration file, and add the necessary columns to the table.

public function up()
    {
        Schema::create('sellers', function (Blueprint $table) {
          $table->increments('id');
          $table->string('name');
          $table->string('email')->unique();
          $table->string('password');
          $table->rememberToken();
          $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('sellers');
    }

Now we can run the migrations, this will create Sellers table along with other tables if any.

php artisan migrate

Setting Expectations

"In this series first we would be setting our exceptions, then would work together to accomplish them."

Lets begin by adding registration related routes in web routes of our project. Open routes/web.php file and add the below routes for now.

//web.php

//other routes

Route::get('seller_register', 'SellerAuth\RegisterController@showRegistrationForm');
Route::post('seller_register', 'SellerAuth\RegisterController@register');

Route::get('/seller_home', function(){
  return view('seller.home');
});

You can replace the URL term seller_register with a name of your choice, but you have to be consistent with this name to avoid confusion.

Accomplish the Expectations

Now let’s work on the first route Route::get('seller_register', 'SellerAuth\RegisterController @showRegistrationForm'); . It says when GET request is made for seller_register page, laravel will call showRegistrationForm() method of SellerAuth\RegisterController.

Lets create our RegisterController for seller

php artisan make:controller SellerAuth/RegisterController

Lets begin editing our Registration controller (SellerAuth/RegisterController) by adding showRegistrationForm()

//RegisterController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class RegisterController extends Controller
{
  //shows registration form to seller
  public function showRegistrationForm()
  {
      return view('seller.auth.register');
  }
}

Now we need to create our view, let’s begin with adding seller folder in the resources/views folder where we shall place all our views related to seller’s login and registration.

Before creating our registration page, let’s first create a layout.blade.php file in seller folder, which will be used by other views.

layouts

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'MultiAuth') }}</title>

    <!-- Styles -->
    <link href="/css/app.css" rel="stylesheet">

    <!-- Scripts -->
    <script>
        window.Laravel = <?php echo json_encode([
            'csrfToken' => csrf_token(),
        ]); ?>
    </script>
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-default navbar-static-top">
            <div class="container">
                <div class="navbar-header">

                    <!-- Collapsed Hamburger -->
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse">
                        <span class="sr-only">Toggle Navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>

                    <!-- Branding Image -->
                    <a class="navbar-brand" href="{{ url('/') }}">
                        {{ config('app.name', 'Laravel') }}
                    </a>
                </div>

                <div class="collapse navbar-collapse" id="app-navbar-collapse">
                    <!-- Left Side Of Navbar -->
                    <ul class="nav navbar-nav">
                        &nbsp;
                    </ul>

                    <!-- Right Side Of Navbar -->
                    <ul class="nav navbar-nav navbar-right">
                        <!-- Authentication Links -->
                        @if (Auth::guard('web_seller')->guest())

                            <!--Seller Login and registration Links -->

                            <li><a href="{{ url('/seller_login') }}">Seller Login</a></li>
                            <li><a href="{{ url('/seller_register') }}">Seller Registration</a></li>
                        @else
                            <li class="dropdown">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                                    {{ Auth::guard('web_seller')->user()->name }} <span class="caret"></span>
                                </a>

                                <ul class="dropdown-menu" role="menu">
                                    <li>
                                        <a href="{{ url('/seller_logout') }}"
                                            onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                            Logout
                                        </a>

                                        <form id="logout-form" action="{{ url('/seller_logout') }}" method="POST" style="display: none;">
                                            {{ csrf_field() }}
                                        </form>
                                    </li>
                                </ul>
                            </li>
                        @endif
                    </ul>
                </div>
            </div>
        </nav>

        @yield('content')
    </div>

    <!-- Scripts -->
    <script src="/js/app.js"></script>
</body>
</html>

We have defined new URLs and a strange word Auth::guard('web_seller'), do not worry we will cover them one by one.

Now let’s create the register.blade.php view in seller/auth folder, which laravel came across at showRegistrationForm() method in RegisterController.

Register

@extends('seller.layouts')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-success">
                <div class="panel-heading">Register A Seller</div>
                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ url('/seller_register') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
                            <label for="name" class="col-md-4 control-label">Name</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}" required autofocus>

                                @if ($errors->has('name'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('name') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Password</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-success">
                                    Register Seller
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Lets work on the next route Route::post('seller_register', 'SellerAuth\RegisterController@register');, where we handle data POST’ed from register view. Let’s create register() method in our RegisterController.

//RegisterController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class RegisterController extends Controller
{
    //shows registration form to seller
    public function showRegistrationForm()
    {
        return view('seller.auth.register');
    }

  //Handles registration request for seller
    public function register(Request $request)
    {

       //Validates data
        $this->validator($request->all())->validate();

       //Create seller
        $seller = $this->create($request->all());

        //Authenticates seller
        $this->guard()->login($seller);

       //Redirects sellers
        return redirect($this->redirectPath);
    }
}

Ok. Thats a lot of steps for one method, we will go through one step at a time.

The first step taken by this method is validation of the request sent from register view via validator() method. Therefore let’s create the validator() method in our RegisterController.


//RegisterController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Validator facade used in validator method
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{
    //shows registration form to seller
    public function showRegistrationForm()
    {
        return view('seller.auth.register');
    }

  //Handles registration request for seller
    public function register(Request $request)
    {

       //Validates data
        $this->validator($request->all())->validate();

       //Create seller
        $seller = $this->create($request->all());

        //Authenticates seller
        $this->guard()->login($seller);

       //Redirects sellers
        return redirect($this->redirectPath);
    }

    //Validates user's Input
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|max:255',
            'email' => 'required|email|max:255|unique:sellers',
            'password' => 'required|min:6|confirmed',
        ]);
    }
}

The next step taken by register() method is creation of seller . We need declare create() method for this purpose in RegisterController.

//RegisterController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Validator facade used in validator method
use Illuminate\Support\Facades\Validator;

//Seller Model
use App\Seller;

class RegisterController extends Controller
{
    //shows registration form to seller
    public function showRegistrationForm()
    {
        return view('seller.auth.register');
    }

  //Handles registration request for seller
    public function register(Request $request)
    {

       //Validates data
        $this->validator($request->all())->validate();

       //Create seller
        $seller = $this->create($request->all());

        //Authenticates seller
        $this->guard()->login($seller);

       //Redirects sellers
        return redirect($this->redirectPath);
    }

    //Validates user's Input
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|max:255',
            'email' => 'required|email|max:255|unique:sellers',
            'password' => 'required|min:6|confirmed',
        ]);
    }

    //Create a new seller instance after a validation.
    protected function create(array $data)
    {
        return Seller::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
    }

}

A seller is created for our application. The next step would be to login this seller.

Laravel's authentication facilities are made up of guards and user providers. Guards define how users are authenticated for each request. Lets create a guard() method in our controller which will return our custom guard for seller. This will be called in the next step of register() method.

//RegisterController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Validator facade used in validator method
use Illuminate\Support\Facades\Validator;

//Seller Model
use App\Seller;

//Auth Facade used in guard
use Auth;

class RegisterController extends Controller
{
    //shows registration form to seller
    public function showRegistrationForm()
    {
        return view('seller.auth.register');
    }

  //Handles registration request for seller
    public function register(Request $request)
    {

       //Validates data
        $this->validator($request->all())->validate();

       //Create seller
        $seller = $this->create($request->all());

        //Authenticates seller
        $this->guard()->login($seller);

       //Redirects sellers
        return redirect($this->redirectPath);
    }

    //Validates user's Input
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|max:255',
            'email' => 'required|email|max:255|unique:sellers',
            'password' => 'required|min:6|confirmed',
        ]);
    }

    //Create a new seller instance after a validation.
    protected function create(array $data)
    {
        return Seller::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
    }

    //Get the guard to authenticate Seller
   protected function guard()
   {
       return Auth::guard('web_seller');
   }

}

Ok, I know what you might me thinking, what is Auth::guard('web_seller'), the Auth::guard() method is used by laravel for authentication, this returns default guard which can authenticate users. But we want to authenticate sellers, so we have tell laravel to authenticate our sellers with our custom guard ‘web_seller’.

So, let us now create our custom guard ‘web_seller’, let’s begin with adding new User Provider for our custom guard. The user provider tells laravel about the model/table it has to refer for custom guard.

To do this open the config/auth.php file and add new user provider seller to providers array.

//auth.php

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

       //Seller user provider
        'sellers' => [
            'driver' => 'eloquent',  //We are using eloquent model
            'model' => App\Seller::class,
        ],
    ],

Now let’s create our new custom guard in the guards array of the same page config/auth.php. We need to specify the guard driver and user provider for our guard. We will be using session as guard driver (This tutorial is about session based login) and seller as user provider which we have already defined.

//auth.php

 'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

      //Our new custom driver.
        'web_seller' => [
            'driver' => 'session',
            'provider' => 'sellers',
        ],
],

Our custom guard is ready to be used by laravel for authenticating sellers. The last step taken by our register() method in RegisterController is redirecting seller to a page when login is successful.

So, let’s declare the redirectPath property for the seller in RegisterController, this will redirect sellers to their home page.

//RegisterController.php

namespace App\Http\Controllers\SellerAuth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

//Validator facade used in validator method
use Illuminate\Support\Facades\Validator;

//Seller Model
use App\Seller;

//Auth Facade used in guard
use Auth;

class RegisterController extends Controller
{

    protected $redirectPath = 'seller_home';

    //shows registration form to seller
    public function showRegistrationForm()
    {
        return view('seller.auth.register');
    }

  //Handles registration request for seller
    public function register(Request $request)
    {

       //Validates data
        $this->validator($request->all())->validate();

       //Create seller
        $seller = $this->create($request->all());

        //Authenticates seller
        $this->guard()->login($seller);

       //Redirects sellers
        return redirect($this->redirectPath);
    }

    //Validates user's Input
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|max:255',
            'email' => 'required|email|max:255|unique:sellers',
            'password' => 'required|min:6|confirmed',
        ]);
    }

    //Create a new seller instance after a validation.
    protected function create(array $data)
    {
        return Seller::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
    }

    //Get the guard to authenticate Seller
   protected function guard()
   {
       return Auth::guard('web_seller');
   }

}

We have defined our redirect property and have previously defied the view for it in our route Route::get('/seller_home', function(){ return view('seller.home');});

So let’s create a new view home.blade.php in the seller folder of views.

Home

@extends('seller.layouts')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-success">
                <div class="panel-heading">Seller's Dashboard</div>

                <div class="panel-body">
                    Greetings.. Seller
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Looks like we are finally done with all our steps for registering a new seller. But we are expecting an error, you might be wondering why. Laravel expects the user provider used by our custom guard to be an instance of Illuminate\Contracts\ Auth\Authenticatable but we have provided it App\Seller class, therefore it will throw an error message, test out what we accomplished till now if you don’t trust me :)

To correct this problem, we need to extend Illuminate\Foundation\Auth\User class in our Seller Model. This class implements Illuminate\Contracts\ Auth\Authenticatable interface and has declared all the necessary methods.

So let’s extend Illuminate\Foundation\Auth\User class and add mass assignable & hidden attributes in our Seller Model (app/Seller.php).

//Seller.php

namespace App;

//Class which implements Illuminate\Contracts\Auth\Authenticatable
use Illuminate\Foundation\Auth\User as Authenticatable;

class Seller extends Authenticatable
{
  //Mass assignable attributes
  protected $fillable = [
      'name', 'email', 'password',
  ];

  //hidden attributes
   protected $hidden = [
       'password', 'remember_token',
   ];

}

End of Chapter

Everything looks great, let’s test our application.

Registration Home Page

We have successfully registered a new Seller and logged him/her in to the system.

For practice, repeat this process for a new type of user model.

But wait, how do we log seller out of the system and login existing sellers... We cover these two topics in next chapter..