swp swp - 1 month ago 11
PHP Question

Laravel 5.5 Multi Authentication Routing Issue

Trying to get Laravel multiple authentication to work using Doctrine instead of Eloquent. I've tried multiple things but keep getting stuck. I currently have two guards defined, two models, two login controllers, etc. If I enable either one or the other, they work. If I try both at the same time, only the default guard seems to work. When I try to access the other guard, I get redirected to the wrong login page.

If I go to /login - works as expected

If I go to /home (without being logged in) - redirected to /login as expected

If I go to /register- works as expected

If I go to /admin/login - works as expected

If I go to /admin/register - works as expected

If I go to /admin (without being logged in) - fail - should get redirected to /admin/login but instead getting redirected to /login

I'm sure I'm missing something simple. Everything works individually. It's just getting the /admin route to use the right middleware...I think...maybe?

My routes file:

Auth::routes();

// staff authentication routes
Route::group( [ 'middleware' => [ 'web' ] ], function() {
Route::get( 'admin/login', 'Auth\StaffLoginController@showLoginForm' );
Route::post( 'admin/login', [ 'as' => 'staff.login', 'uses' => 'Auth\StaffLoginController@login' ] );
Route::get( 'admin/register', 'Auth\StaffRegisterController@showRegistrationForm' );
Route::post( 'admin/register', [ 'as' => 'staff.register', 'uses' => 'Auth\StaffRegisterController@register' ] );

Route::group( [ 'middleware' => [ 'staff' ] ], function() {
Route::get( '/admin', 'AdminController@index' )->name( 'admin' );
});
});

Route::get('/home', 'HomeController@index')->name('home');


I've tried various route definitions but this is the latest iteration. None of the previous iterations worked either.

My auth file:

'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],

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

'api' => [
'driver' => 'token',
'provider' => 'users',
],

'staff' => [
'driver' => 'session',
'provider' => 'adminusers',
]
],

'providers' => [
'users' => [
'driver' => 'doctrine',
'model' => App\Users\Customer::class,
],
'adminusers' => [
'driver' => 'doctrine',
'model' => App\Users\Staff::class,
]
],

'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
'adminusers' => [
'provider' => 'adminusers',
'table' => 'password_resets',
'expire' => 30,
],
],


My LoginController (basically same as out of the box):

class LoginController extends Controller {
use AuthenticatesUsers;

protected $redirectTo = '/home';

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


My StaffLoginController:

<?php

class StaffLoginController extends Controller {
use AuthenticatesUsers;

protected $redirectTo = '/admin';

protected $guard = 'staff';

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

public function showLoginForm() {
return view( 'auth.staff.login' );
}

public function login( Request $request ) {
$this->validate( $request, [
'email' => 'required|email',
'password' => 'required',
]);

if( auth()->guard( 'staff' )->attempt( [
'email' => $request->input( 'email' ),
'password' => $request->input( 'password' ),
])) {
return view( 'staff' );
} else {
return view( 'auth.staff.login' )->withErrors( [ 'email' => 'Authentication failed' ] );
}
}

protected function guard() {
return \Auth::guard( 'staff' );
}
}


My AdminController:

class AdminController extends Controller {
public function __construct() {
$this->middleware( 'auth:staff' );
}

public function index() {
return view( 'staff' );
}
}


My RedirectIfStaffUnauthenticated middleware (which is registered in Http\Kernel.php routeMiddleware as 'staff' => \SNJ\Http\Middleware\RedirectIfStaffUnauthenticated::class, ):

class RedirectIfStaffUnauthenticated {
public function handle( $request, Closure $next, $guard = 'staff' ) {
if ( !Auth::guard( $guard )->check() ) {
return view( 'auth.staff.login' );
}

return $next( $request );
}
}


UPDATE:

Changed routes in web.php to be as thus (removed the middleware from the admin/login and admin/register routes:

Auth::routes();

// staff authentication routes
Route::get( 'admin/login', 'Auth\StaffLoginController@showLoginForm' );
Route::post( 'admin/login', [ 'as' => 'staff.login', 'uses' => 'Auth\StaffLoginController@login' ] );
Route::get( 'admin/register', 'Auth\StaffRegisterController@showRegistrationForm' );
Route::post( 'admin/register', [ 'as' => 'staff.register', 'uses' => 'Auth\StaffRegisterController@register' ] );

Route::group( [ 'middleware' => [ 'staff' ] ], function() {
Route::get( '/admin', 'AdminController@index' )->name( 'admin' );
});

Route::get('/home', 'HomeController@index')->name('home');


No change. Still doesn't work.

Tried changing routes thusly (put all admin routes into 'staff' middleware:
Auth::routes();

// staff authentication routes

Route::group( [ 'middleware' => [ 'staff' ] ], function() {
Route::get( 'admin/login', 'Auth\StaffLoginController@showLoginForm' );
Route::post( 'admin/login', [ 'as' => 'staff.login', 'uses' => 'Auth\StaffLoginController@login' ] );
Route::get( 'admin/register', 'Auth\StaffRegisterController@showRegistrationForm' );
Route::post( 'admin/register', [ 'as' => 'staff.register', 'uses' => 'Auth\StaffRegisterController@register' ] );
Route::get( '/admin', 'AdminController@index' )->name( 'admin' );
});

Route::get('/home', 'HomeController@index')->name('home');


Same same. Still doesn't work.

Answer Source

Change your StaffLoginController to this,

    <?php

class StaffLoginController extends Controller {
  use AuthenticatesUsers;

  public function showLoginForm() {
    return view( 'auth.staff.login' );
  }

  public function login( Request $request ) {
    $this->validate( $request, [
      'email' => 'required|email',
      'password' => 'required',
    ]);

    if( auth()->guard( 'staff' )->attempt( [
      'email' => $request->input( 'email' ),
      'password' => $request->input( 'password' ),
    ])) {
      return view( 'staff' );
    } else {
      return view( 'auth.staff.login' )->withErrors( [ 'email' => 'Authentication failed' ] );
    }
  }
}

remove constructor from AdminController, we are later going to call this middleware on routes.

class AdminController extends Controller {

  public function index() {
    return view( 'staff' );
  }
}

You don't need to pass the guard value to auth middleware since you already defined as second middleware for authenticating admin routes.

update your staff middleware like this.

class RedirectIfStaffUnauthenticated {
  public function handle( $request, Closure $next, $guard = null ) {
    if ( Auth::guard( $guard )->check() ) {

if(! $guard == 'staff')
                {
                    return redirect()->route( 'staff.login.form' ); 
                }
     }else return redirect()->route( 'staff.login.form' ); 

    return $next( $request );
  }
}

Now update your routes.

Route::get( 'admin/login', 'Auth\StaffLoginController@showLoginForm' );
Route::post( 'admin/login', [ 'as' => 'staff.login.submit', 'uses' => 'Auth\StaffLoginController@login' ] );
Route::get( 'admin/register', 'Auth\StaffRegisterController@showRegistrationForm' );
Route::post( 'admin/register', [ 'as' => 'staff.register.submit', 'uses' => 'Auth\StaffRegisterController@register' ] );
Route::group( [ 'middleware' => [ 'staff' ] ], function() {
  Route::get( '/admin', 'AdminController@index' )->name( 'admin' );
});

Also add the following lines to your unauthenticated function in Handler.php file in app\Exceptions

$guard = array_get($exception->guards(), 0);
        switch ($guard) {
      case 'staff':
        $login = 'admin/login';
        break;
    case 'users':
        $login = 'login';
        break;
      default:
        $login = 'login';
        break;
    }
    return redirect()->guest(route('login'));

Please check your app/Kernel.php, you can see that guest is an alias for app/Http/Middleware/RedirectIfAuthenticated.php middleware.

You don't need to call constructors on both web.php file and on the controllers constructor.

Here the RedirectIfStaffUnauthenticated middleware checks the root /admin is authenticated and it has a guard value of staff, if not it will redirect to the /admin/login route.

Please read laravel doc for clarification

Hope this helps.