Hi, in this post I will dive in the auth scaffold to redirect users to different areas by roles.
Add Role column to users.
User migration:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('role')->default('user');
$table->rememberToken();
$table->timestamps();
});
}
User model:
class User extends Authenticatable
{
use Notifiable, HasApiTokens;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password', 'role',
];
}
AuthController
By adding the auth scaffold, Laravel provide us with Auth controllers for authentication, register, forgot password, etc, the controllers are located in "app/Http/Controllers/Auth", here we can find the "LoginController.php" file, here we can find the property:
protected $redirectTo = RouteServiceProvider::HOME;
This means that we can find a RouteServiceProvider const named "HOME", we can override this const and it will change the redirect endpoint after login, but this is not what we need to redirect users by role or by any other condition.
The LoginController use a trait:
use AuthenticatesUsers;
This AuthenticatesUsers trait has another trait "RedirectsUsers" this RedirectsUsers trait has a method "redirectPath":
public function redirectPath()
{
if (method_exists($this, 'redirectTo')) {
return $this->redirectTo();
}
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}
So it means that this trait looks if the class has a "redirectTo" property and if this is not the case it execute a "redirectTo" method, so we can add the method "redirectTo" in LoginController to add any logic that we need.
By example:
public function redirectTo()
{
$for = [
'admin' => 'admin.panel',
'user' => 'foundations.splashscreen',
];
return $this->redirectTo = route($for[auth()->user()->role]);
}
Here you can see an array with roles as keys and route name as value, I strongly suggest that use the "route()" method, because if you change the endpoint it does not affect this method, because the value that we are resolving dinamically is the route name, not the endpoint.
Note:
If you need to use some "dd()" debug the endpoint that will be redirect you can go to the trait "AuthenticatesUsers.php" that is used by "LoginController" here we can find a method "sendLoginResponse", that use the method redirectPath():
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
if ($response = $this->authenticated($request, $this->guard()->user())) {
return $response;
}
// HERE YOU CAN ADD a dd($this->redirectPath())
return $request->wantsJson()
? new Response('', 204)
: redirect()->intended($this->redirectPath());
}
Note:
If you want to redirect authenticated users on authentication routes by role to different paths, just edit the "RedirectIfAuthenticated" middleware to redirect by different roles.
Top comments (3)
Hello Ariel.
Thanks for the post.
I noticed that the login page needs to be the entry point for the user.
If i'm not logged and use the root url "mydomain.app", I'm redirected to "mydomain.app/login", then I log in, and since my first intended URL was the root one, the redirection is override by the root one.
I found this when looking at the "intended()" function in the sendLoginResponse() one.
Hello Ariel, what version of Laravel would this example apply?
Hi, the example was created with Laravel 7 using "laravel/ui" package, its an official package, with Laravel 8 you can still working with "laravel/ui" package or use Jetstream, that use "hooks" some method to override behavior without coverriding class methods directly, the example works perfectly on "laravel/ui", if you prefer jetstream go to official jetstream docs to get more info about it.