Latheesan
Latheesan

Reputation: 24116

Implementing native multi auth (user vs admin) using guards in Laravel 5.5 - guest middle ware uses hard coded named route

I would like to implement native multi authentication in my application for two types of users: User and Admin.

  1. I started implementing a new admins table migration (by copying the existing create_users_table).

  2. I created a new model called Admin (by copying the existing User model)

  3. Both (User and Admin) models were updated to specify which guards they use like this:

User Model

protected $guarded  = ['user'];

Admin Model

protected $guarded  = ['admin'];
  1. Then I setup the auth configuration like this:

config/auth.php

https://pastebin.com/iLAZbX2z

  1. Then I defined my custom auth routes for users and admins like this:

routes/web.php

https://pastebin.com/raw/CKX9Xddb

  1. Finally, I defined the auth protected routes for the two user types like this:

routes/web.php

// User auth protected pages
Route::prefix('manage')->middleware('auth:user')->namespace('Manage')->group(function() {

    Route::get('/', 'DashboardController@index');

});

// Admin auth protected pages
Route::prefix('admin')->middleware('auth:admin')->namespace('Admin')->group(function() {

    Route::get('/', 'DashboardController@index');

});

I tested the user login first before proceeding (there's more to be done to get admin to login), by going into http://myapp.local/login and entering my credentials and I was successfully redirected to user's dashboard (i.e. http://myapp.local/manage). All of the user specific functionality (e.g. reset pass) etc.. are all working fine).

However; when testing the guest middleware by visiting http://myapp.local/manage directly, I expected to be redirected to http://myapp.local/login but got an error instead:

Route [login] not defined.

This error is valid; because in the routes definition, I've named the user login as user.login

It looks like the guest middleware uses a hard coded named route called login in the unauthenticated exception handler.

vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php

protected function unauthenticated($request, AuthenticationException $exception)
{
    return $request->expectsJson()
                ? response()->json(['message' => $exception->getMessage()], 401)
                : redirect()->guest(route('login')); // <------
} 

How can I tell the guest middleware to use a differently named route for the login (when un-authenticated user tries to visit a auth protected page)?

I will need to use this later for the admin guest middleware also.

Upvotes: 1

Views: 616

Answers (3)

Latheesan
Latheesan

Reputation: 24116

Thanks to Sohel0415's answer; I realised that the App\Exceptions\Handler extends the vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php, which means I can solve it like this:

I've edited the app\Exceptions\Handler.php like this:

  1. Included this use statement at the top:

use Illuminate\Auth\AuthenticationException;

  1. Added this method:

https://pastebin.com/raw/10Y1tS6d

Upvotes: 1

Sohel0415
Sohel0415

Reputation: 9853

Use Request::is() to check the requested url, then redirect :

protected function unauthenticated($request, AuthenticationException $exception)
{
      if(\Request::is('manage/*')){
      return $request->expectsJson()
            ? response()->json(['message' => $exception->getMessage()], 401)
            : redirect()->guest(route('user.login'));
      }
      else if(\Request::is('admin/*')){
        return $request->expectsJson()
            ? response()->json(['message' => $exception->getMessage()], 401)
            : redirect()->guest(route('admin.login'));
      }
      else{
        return $request->expectsJson()
            ? response()->json(['message' => $exception->getMessage()], 401)
            : redirect()->guest(route('login'));
      }
}

Note: add this method in App\Exceptions\Handler

Upvotes: 0

Alexey Mezenin
Alexey Mezenin

Reputation: 163748

I've named the user login as user.login

You're getting the error because the route name is user.login and you're trying to use login route. So, use proper route name here:

redirect()->guest(route('user.login')); 

Upvotes: 0

Related Questions