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
- Runin the console to create the authentication scaffolding. For Laravel 6 and higher use:
php artisan make:auth
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 commandand to the class (migration file), add the required fields based on the application’s requirement. Here, we would take the following:
php artisan make:migration create_admins_table
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 usingand the class Admin.php will be created in App directory; add the following code:
php artisan make:model Admin
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 beWe add the following to the migration file:
php artisan make:migration create_users_table
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,
Route::prefix(‘admin’)->group(function (){
Route::get('/index,'HomeController@index')->name('home');
}
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
?PHP
namespace App\Http\Controllers\Admin\Auth;
use Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
public function __construct(){
$this->middleware('guest:admin')->except('logout');
}
/**
* Show the login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm()
{
return view(“”); //name of the admin login view
}
/**
* Login the admin.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function login(Request $request)
{
//validation...
//login for admin...
//redirect to...
}
protected function guard(){
return Auth::guard('admin');
}
/**
* Logout the admin.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function logout()
{
//logout the admin…
Auth::guard('admin')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
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:
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 $next * @param 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.