In this tutorial i will walk you through implementing multiguard authentication using laravel 12+.
Below are the steps we will have to follow.
- Create the model and migration for both admin and users.
- Create the required guards.
- Define the routes and controllers.
- Configure the redirects for the guards.
- Logout
- Conclusion
Creating the model
We need to have the models we want to create. Make sure that the models extend from the Illuminate\Foundation\Auth\User
class
User model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
Admin model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Admin extends Authenticatable
{
use HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
Create the required guards
In config/auth.php, define the required guards. The default guard is web while we will define and extra one as admin. Also here we are adding a new admins provider pointing to the App\Models\Admin
class
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\User::class),
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
Define the routes and controllers.
Next we define our routes. So here we have the the basic routes. You'll notice that we have the custom guard that we defined.
<?php
use App\Http\Controllers\AdminDashboardController;
use App\Http\Controllers\AdminLoginController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\LoginController;
use Illuminate\Support\Facades\Route;
Route::middleware('guest')->group(function () {
Route::get('login', [LoginController::class, 'loginForm'])->name('login');
Route::post('login', [LoginController::class, 'login'])->name('login-user');
});
Route::middleware('guest:admin')->group(function () {
Route::get('/admin/login', [AdminLoginController::class, 'loginForm'])->name('admin.login');
Route::post('/admin/login', [AdminLoginController::class, 'login'])->name('admin.login-admin');
});
Route::middleware('auth')->get('dashboard', DashboardController::class)->name('dashboard');
Route::middleware('auth:admin')->get('/admin/dashboard', AdminDashboardController::class)->name('admin.dashboard');
The LoginController
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
public function loginForm()
{
return view('login');
}
public function login()
{
$user = User::first();
Auth::login($user);
return redirect()->route('dashboard');
}
}
The AdminLoginController
<?php
namespace App\Http\Controllers;
use App\Models\Admin;
use Illuminate\Support\Facades\Auth;
class AdminLoginController extends Controller
{
public function loginForm()
{
return view('admin.login');
}
public function login()
{
$admin = Admin::first();
Auth::guard('admin')->login($admin);
return redirect()->route('admin.dashboard');
}
}
Configure the redirects for the guards
You'll notice that when you are not logged in and you try to access the /admin/dashboard as a guest you get redirected to /login instead of /admin/login. So how do we get redirected to the desired urls?
So for that we have to replace the auth and guest aliases in bootstrap/app.php.
So auth aliases the \Illuminate\Auth\Middleware\Authenticate' middleware while the guest aliases the
\Illuminate\Auth\Middleware\RedirectIfAuthenticated' middleware.
To configure the redirects, we are going to create our own Authenticate and RedirectIfAuthenticated middleware.
php artisan make:middleware Authenticate
php artisan make:middleware RedirectIfAuthenticated
Now replace the aliases with these new middleware.
<?php
use App\Http\Middleware\Authenticate;
use App\Http\Middleware\RedirectIfAuthenticated;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__ . '/../routes/web.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'guest' => RedirectIfAuthenticated::class,
'auth' => Authenticate::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
Now for the RedirectIfAuthenticated middleware, in the handle method we just have to set the required destination route if the requesting guard is admin or web.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Auth\Middleware\RedirectIfAuthenticated as MiddlewareRedirectIfAuthenticated;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class RedirectIfAuthenticated extends MiddlewareRedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, ...$guards): Response
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
switch ($guard) {
case 'admin':
return redirect()->route('admin.dashboard');
break;
default:
return redirect()->route('dashboard');
}
}
}
return $next($request);
}
}
Now for the for the Authenticate middleware it's a bit different. We have to modify the $redirectTo
parameter of the AuthenticationException
that is thrown when the unauthenticated
method is called
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Auth\Middleware\Authenticate as MiddlewareAuthenticate;
class Authenticate extends MiddlewareAuthenticate
{
protected function unauthenticated($request, array $guards)
{
foreach ($guards as $guard) {
switch ($guard) {
case 'admin':
throw new AuthenticationException(redirectTo: route('admin.login'));
break;
default:
throw new AuthenticationException(redirectTo: route('login'));
}
}
}
}
Logout
To logout you just call the guards.
Auth::guard('admin')->logout();
Auth::guard('web')->logout();
Conclusion
And voilà. We now have redirects working as they should. You now have a working multi-guard authentication system. You can add as many models as you choose. You can access the code here.
Top comments (0)