Search code examples
phplaravelauthenticationrolesuser-roles

Laravel 7 - Redirecting different user roles to different view


  • The LoginController had this code before:

    class LoginController extends Controller
    {
        public function showLoginForm(){
            $roles = Role::all();
            return view('auth.login', compact('roles'));
        }
    
        public function logout(Request $request){
            Auth::logout();
            $request->session()->flush();
            return redirect('/');
        }
    
        public function login()
        {
            $credentials = $this->validate(request(),[
                'email' => 'email|required|string',
                'password' => 'required|string',
            ]);
    
           
            if (Auth::attempt ($credentials)){//auth attemptdevuelve verdadero o falso en caso de que las credenciales correspondan o no
            //Inician cambios RDAN
            $user = Auth::user();
            if($user->userRole() == 'admin') {
                return redirect('main');
            } else if($user->userRole() == 'externo') {
                return redirect('es/user_form');
            } else if($user->userRole() == 'profesor') {
                return redirect('profesor_site');
            } else if($user->userRole() == 'registrador') {
                return redirect('select_lang');
            } else {
                return back()->withErrors(['email' => 'Incorrect user permissions']) 
                ->withInput(request(['email']));
            }
            //Terminan cambios RDAN
                    
            }else{
            return back()->withErrors(['email' => 'Incorrect user permissions']) 
            ->withInput(request(['email'])); }
        }
    }

  • Then I changed it for:

    class LoginController extends Controller
    {
      use AuthenticatesUsers;
    
        /**
         * Where to redirect users after login.
         *
         * @var string
         */
        protected $redirectTo = '/main';//RouteServiceProvider::HOME;
    
        /**
         * Create a new controller instance.
         *
         * @return void
         */
        public function __construct()
        {
            $this->middleware('guest')->except('logout');
        }
    }
  • In the model User I have this for the roles:
     public function roles()
        {
            return $this->belongsToMany(Role::class,'assigned_roles');
        }
    
        public function isAdmin(){
            return $this->hasRoles(['admin']);
        }
    
        public function hasRoles(array $roles)
        {
            return $this->roles->contains(fn($role, $key) => in_array($role->name, $roles));
        }
    
        public function userRole(){
            return $this->role->nombre_rol;
        }

With the new changes on the LoginController I have no problem with the login, but obviously only redirect to the main view. So, I want to add the redirect view depend on the role, but when I add the public function login() that it had before it returns an error with the function userRole() on the model User. The error is

ErrorException Trying to get property 'nombre_rol' of non-object http://localhost/Servescol2.0.2/public/login


Solution

  • You don't need to override the login method. The login method currently will make a call to the authenticated method to see if it returns true truthy value and then return that as the response. You can override the authenticated method and have it return your redirect based on your conditions.

    protected function authenticated(Request $request, $user)
    {
        if ($user->hasRoles(['admin'])) {
            return redirect('main');
        }
        ...
    }
    

    The error is caused by trying to access an attribute/relationship which doesn't exist, which returns null:

    $this->role
    

    The User belongs to many Role so there are multiple roles not a single one.

    You could have a method to check for a single role:

    public function hasRole($role)
    {
        return $this->roles->contains('name', $role);
    }
    

    Then you could adjust your conditionals:

    if ($user->hasRole('admin')) {
    

    Or use the hasRoles method instead:

    if ($user->hasRoles(['admin']) {