Multiple Authentication in Laravel

Basically, authentication can be considered as a process to identify and recognize user credentials. There are applications that require different database tables for separation of roles and permissions that differentiate the users. Laravel allows multiple authentication to achieve this smoothly along with a clean code. The following will help accomplish this for Laravel projects.

Setup

  • Create a project using :
    composer create-project --prefer-dist laravel/laravel project-name
  • Configure the database in the .env file:
    DB_DATABASE= database name
    DB_USERNAME=username
    DB_PASSWORD=password
    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
  • Run
    php artisan make:auth
    in the console to create the authentication scaffolding. For Laravel 6 and higher use:
    composer require laravel/ui
    php artisan ui vue --auth

Model and Migrations

For this example, we will have two tables viz, admins and users. Both these tables will have separate models, migrations and controllers. The view files can or cannot be the same, that is, if the auth pages for both the tables are similar then the logic can be separated conditionally and if they are different, we can use different files.

Admin

  • For admins table migration, run the command
    php artisan make:migration create_admins_table
    and to the class (migration file), add the required fields based on the application’s requirement. Here, we would take the following:
    public function up()
    {
     Schema::create('admins', 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('admins');
    }
  • Now, run php artisan migrate to migrate the table.
  • Now create a model for admin using
    php artisan make:model Admin
    and the class Admin.php will be created in App directory; add the following code:
    namespace App;
     
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    use Illuminate\Notifications\Notifiable;
     
    class Admin extends Authenticatable
    {
      use Notifiable;
      protected $guard = 'admin';
      protected $fillable = ['name', 'email', 'password'];
      protected $hidden = ['password', 'remember_token'];
    }


    The guard name is specified when we don’t want to use the default guard (guards are explained below).

Users

  • For users table migration, the command would be
    php artisan make:migration create_users_table
    We add the following to the migration file:
    public function up() 
    { 
           Schema::create('users', function (Blueprint $table) 
           {   
                 $table->bigIncrements('id');   
                 $table->string('name');   $table->string('email')->;unique();   
                 $table->string('password');   $table->rememberToken();   
                 $table->timestamps();  }); 
    } 
    public function down() {   
           Schema::dropIfExists('users'); 
    }
  • Now, run php artisan migrate to migrate the table.
  • Next, create a model for users and add the code given below:
    ?php namespace App; 
     
    use Illuminate\Contracts\Auth\MustVerifyEmail; 
    use Illuminate\Foundation\Auth\User as Authenticatable; 
    use Illuminate\Notifications\Notifiable; 
     
    class User extends Authenticatable {   
     
    use Notifiable;   
    protected $fillable = ['email', 'password', ‘name’];   
    protected $hidden = ['password', 'remember_token'];
     
    }

    Here, we don’t specify the guard and the default one will be taken.

A model extends an eloquent model but we are extending the class Authenticatable. Authenticatable is an alias to User class that is used for authentication in Laravel. The notification trait is included for password reset notification.

Guards Specification

Guards help in identifying the user for authentication for each request. It also manages the authentication for multiple users/tables. By default, Laravel supports two types of authentication – web-based authentication that is session-based and API authentication that is token-based using the guards, web and api respectively.  To specify the guards according to the application’s requirement, go to the config/auth.php file. In this file we have the following:

Defaults: This array allows us to mention the default guard and password. The web guard is used for session-based authentication which is the default one. The passwords array has users that will be used while resetting the password.

Providers: There are two types of drivers, eloquent and database. In general, drivers specify how the user data will be saved and retrieved. If one wants to use the eloquent driver, then the driver eloquent is to be specified along with the model name in the providers array and similarly for database driver specify driver as database along with table name.

Passwords: The passwords array includes the specification for password reset. It includes the provider and model or table name as explained above; the expire has the value in minutes for token expiry time which is set 60 by default but can be changed.

So, the config/auth.php file looks like:

?php
 
return [
    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
 
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
 
    	'admin' => [
    		'driver' => 'session',
    		'provider' => 'admin',
    	],
    ],
 
 
//to specify driver database and include table name
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
 
    	'admin' => [
    		'driver' => 'eloquent',
    		'model' => App\Admin::class,
    	],
 
        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],
 
   'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],
    'password_timeout' => 10800,
 
];

Routes

Authentication Routes for Admin

Let’s create a sub-directory for Admin and put the admin controllers in it. Now, using the prefix method, specify the routes for the admin. For example,

  1. Route::prefix(‘admin’)->group(function (){
  2. Route::get('/index,'HomeController@index')->name('home');
  3. }

This will avoid the repetition of /admin in all the routes. For authentication, we can add the routes within the admin routes group.

Route::namespace('Auth')->group(function(){
 
//Login Routes
Route::get('/login','LoginController@showLoginForm')->name('login');
    Route::post('/login','LoginController@login');
Route::post('/logout','LoginController@logout')->name('logout');
 
//similarly set other routes
}

Views

The  scaffolding has been generated already in the first step. Now, customizations can be made to the layouts files. The blade files concerned with the admin can be put inside a subdirectory created inside the views folder. If the login page for admin is different then a file can be added in this subdirectory otherwise add the admin code to the login.blade.php conditionally.

Controllers

For admin, create the controllers inside the Admin sub-directory, for example,

php artisan make:controller Admin/HomeController


Login Controller
  1. ?PHP
  2.  
  3. namespace App\Http\Controllers\Admin\Auth;
  4.  
  5. use Auth;
  6. use Illuminate\Http\Request;
  7. use App\Http\Controllers\Controller;
  8. use Illuminate\Foundation\Auth\ThrottlesLogins;
  9. use Illuminate\Foundation\Auth\AuthenticatesUsers;
  10.  
  11. class LoginController extends Controller
  12. {
  13. public function __construct(){
  14.     $this->middleware('guest:admin')->except('logout');
  15. }
  16. /**
  17. * Show the login form.
  18. *
  19. * @return \Illuminate\Http\Response
  20. */
  21. public function showLoginForm()
  22. {
  23. return view(“”); //name of the admin login view
  24. }
  25. /**
  26. * Login the admin.
  27. *
  28. * @param \Illuminate\Http\Request $request
  29. * @return \Illuminate\Http\RedirectResponse
  30. */
  31. public function login(Request $request)
  32. {
  33. //validation...
  34. //login for admin...
  35. //redirect to...
  36. }
  37. protected function guard(){
  38.     return Auth::guard('admin');
  39. }
  40. /**
  41. * Logout the admin.
  42. *
  43. * @return \Illuminate\Http\RedirectResponse
  44. */
  45. public function logout()
  46.    {
  47.      //logout the admin…
  48.      Auth::guard('admin')->logout();
  49.  
  50.    $request->session()->invalidate();
  51.  
  52.    $request->session()->regenerateToken();
  53.    return $this->loggedOut($request) ?: redirect('/admin/login');<br>  }}


The AuthenticatesUsers trait handles user authentication.

Middleware

Middleware filters out the HTTP requests entering the application. For authentication, we have a middleware that verifies whether the user is authenticated, if the user is not authenticated then he/she is redirected to the login page. For authentication middleware, like auth and guest, if a guard has to be specified then it should be like auth:guard name or guest:guard name.

For our example, we can add the following in the admin login controller:

public function __construct(){
      $this->middleware('guest:admin')->except('logout');
}

Also, we can add the middleware to the route like:

  1. Route::get('/home','HomeController@index')->name('home')->middleware('auth:admin');


Now, the Authenticate and RedirectIfAuthenticate files in the app/Http/Middleware directory need to be modified so that the user is redirected to the correct routes as per the guards. So the Authenticate.php file will look like:

?PHP
 
namespace App\Http\Middleware;
 
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Route;
 
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param     \Illuminate\Http\Request; $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
if(Route::is('admin.*')){
 return route('admin.login');
 }
 return route('login');
}
}
}


In the RedirectIfAuthenticated.php file, specify the guards and redirect accordingly, as follows:
?php
 
namespace App\Http\Middleware;
 
use App\Providers\RouteServiceProvider;
use Closure;<br>use Illuminate\Support\Facades\Auth;
 
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param     \Illuminate\Http\Request; $request
* @param      \Closure&nbsp; $next
* @param&nbsp; string|null; $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
 if ($guard == "admin" && Auth::guard($guard)->check()) {
 return redirect(/route-name”); //name of the route to be redirected on successful admin login
 }
 if (Auth::guard($guard)->check()) {
 return redirect(/route-name”);//name of the route to be redirected on successful user login
 }
return $next($request);
}
}

Thus, we have covered the concept of separation of logic for users and admins to achieve multiple authentication in Laravel and defined guards to manage and handle multiple authentications and redirections.

Related Post

About the Author

Madhavi Gajjar

Gladly, working as a PHP/Laravel Developer at Regur Technology Solutions. Strives to explore, learn and grow technically and analytically. Loves crafting in free time.