I have a multiple authentication system set up in Laravel 5.7
There is an 'admin' section of the site and a 'learner' section of the site. When you try to access a portion of either site, it redirects you the correct login page if you're not logged in yet.
However, if follow these steps, I come across an issue with the redirects:
It properly logs me in, but improperly redirects to the other login page. The issue also happens vice versa, if I get an automatic redirect to the 'learner' then link directly to the admin login page and log in.
I believe I've narrowed the issue down to the unaunthenticated function I've placed in the Exception/Handler.php file, but I can't figure out where to go from there.
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
return redirect()->guest(route($login));
}
Using each separate login page works fine. It's just when you follow the process above that I see issues.
I use separate middleware in each controller like this:
Admin Home Controller
public function __construct()
{
$this->middleware('auth');
}
Admin login controller:
public function __construct()
{
$this->middleware('guest')->except('logout');
}
Learner home controller
public function __construct()
{
$this->middleware('auth:learner');
}
Learner login Controller:
public function __construct()
{
$this->middleware('guest:learner')->except('logout');
}
Solution: Clearing out the intended url with Session:forget('url.intended');
protected function unauthenticated($request, AuthenticationException $exception)
{
// dd($exception);
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
Session::forget('url.intented');
return redirect()->route($login);
}
Solution: Clearing out the intended url with Session:forget('url.intended');
protected function unauthenticated($request, AuthenticationException $exception)
{
// dd($exception);
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
Session::forget('url.intented');
return redirect()->route($login);
}
Here's an example of what I use in production for an application that has two user classes which both must be logged into access their separate resources. The User class uses the default Laravel Authentication with no changes, however, my Admin class users use this custom middleware:
<?php
namespace App\Http\Middleware;
use App\Admin;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminMiddleware
{
public function handle($request, Closure $next)
{
if (Auth::guest()) {
return redirect(route('admin.login'));
}
if (!$request->user() instanceof Admin) {
return redirect(route('restricted'));
}
return $next($request);
}
}
I registered the AdminMiddleware in the app/Http/Kernel.php
like so:
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\AdminMiddleware::class,
/*** OTHER MIDDLEWARES ARE HERE ***/
];
In the routes/web.php
file I have wrapped the routes like so:
Route::group(['prefix' => 'admin', 'as' => 'admin.', 'middleware' => 'auth:admin'], function () {
/**** ADMIN ROUTES ARE HERE ****/
});
Route::group(['middleware' => 'auth'], function () {
/**** CLIENT ROUTES ARE HERE ****/
});
And I have a custom AdminLoginController which overwrites a the $redirect
path variable as well as the guard()
, showLoginForm()
and redirectTo()
functions and looks like this:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
class AdminLoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/admin/home';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function guard()
{
return Auth::guard('admin');
}
public function showLoginForm()
{
return view('auth.admin.login');
}
public function redirectTo()
{
return route('admin.home');
}
}
Finally in the config/auth.php
I have the following references to guards, providers and passwords:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
'passwords' => [
'admin' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
],
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
Of course this means that my Admins and Users are stored on separate tables in the database, but it works really well without any issues so I'm perfectly okay with that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With