Login only if user is active using Laravel

前端 未结 19 1580
孤城傲影
孤城傲影 2020-11-30 23:26

I\'m currently working on my Laravel app and to prevent spam I decided that only active users are able to login. I\'m currently using Laravel\'s login system just like in La

相关标签:
19条回答
  • 2020-11-30 23:37

    Laravel 5.4 / 5.5

    Override the default login() function by placing this function in your LoginController:

    public function login(\Illuminate\Http\Request $request) {
        $this->validateLogin($request);
    
        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);
            return $this->sendLockoutResponse($request);
        }
    
        // This section is the only change
        if ($this->guard()->validate($this->credentials($request))) {
            $user = $this->guard()->getLastAttempted();
    
            // Make sure the user is active
            if ($user->active && $this->attemptLogin($request)) {
                // Send the normal successful login response
                return $this->sendLoginResponse($request);
            } else {
                // Increment the failed login attempts and redirect back to the
                // login form with an error message.
                $this->incrementLoginAttempts($request);
                return redirect()
                    ->back()
                    ->withInput($request->only($this->username(), 'remember'))
                    ->withErrors(['active' => 'You must be active to login.']);
            }
        }
    
        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);
    
        return $this->sendFailedLoginResponse($request);
    }
    

    Overriding the login() method in this way is recommended over many of the other answers on this question because it allows you to still use many of the more advanced authentication functionality of Laravel 5.4+ such as login throttling, multiple authentication guard drivers/providers, etc. while still allowing you to set a custom error message.


    Laravel 5.3

    Change or override your postLogin() function in your AuthController to look like this:

    public function postLogin(Request $request)
    {
        $this->validate($request, [
            'email' => 'required|email', 'password' => 'required',
        ]);
    
        $credentials = $this->getCredentials($request);
    
        // This section is the only change
        if (Auth::validate($credentials)) {
            $user = Auth::getLastAttempted();
            if ($user->active) {
                Auth::login($user, $request->has('remember'));
                return redirect()->intended($this->redirectPath());
            } else {
                return redirect($this->loginPath()) // Change this to redirect elsewhere
                    ->withInput($request->only('email', 'remember'))
                    ->withErrors([
                        'active' => 'You must be active to login.'
                    ]);
            }
        }
    
        return redirect($this->loginPath())
            ->withInput($request->only('email', 'remember'))
            ->withErrors([
                'email' => $this->getFailedLoginMessage(),
            ]);
    
    }
    

    This code redirects back to the login page with an error message about the user being inactive. If you want to redirect to an authentication page you would change the line I marked with the comment Change this to redirect elsewhere.

    0 讨论(0)
  • 2020-11-30 23:39

    Laravel 5.8 tested. Put this code in your LoginController.php and be happy.

    public function login(Request $request)
    {
        $user = User::where('username',$request->username)->first();
        if( $user && !$user->active){
            return redirect()->back()->with('error','the user has been desactivated');
        }
    
        $this->validateLogin($request);
    
        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);
    
            return $this->sendLockoutResponse($request);
        }
    
        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }
    
        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);
    
        return $this->sendFailedLoginResponse($request);
    }
    
    0 讨论(0)
  • 2020-11-30 23:44

    If someone uses ajax request on login and wants to have custom message, here is how I achieved this in login controller:

    login() function

      // This section is the only change
        if ($this->guard()->validate($this->credentials($request))) {
            $user = $this->guard()->getLastAttempted();
    
            // Make sure the user is active
            if ($user->status == 1 && $this->attemptLogin($request)) {
                // Send the normal successful login response
                return $this->sendLoginResponse($request);
            } else {
                // Increment the failed login attempts and redirect back to the
                // login form with an error message.
                $this->incrementLoginAttempts($request);
                return $this->sendFailedLoginResponse($request, true);
            }
        }
    

    And other functions

     public function sendLoginResponse(Request $request)
    {
        $redirectTo = false;
        if ($request->headers->get('referer') == env('APP_URL') . '/' || $request->headers->get('referer') == env('APP_URL') . '/login') {
            $redirectTo = $this->redirectPath();
        }
    
        if ($request->expectsJson()) {
            return response()->json(['status' => true, 'user' => auth()->user(), 'redirectTo' => $redirectTo, 'fragments' => [
                '#main-nav' => view('includes.nav')->render()
            ]]);
        } else {
            return redirect($redirectTo);
        }
    }
    
    public function sendFailedLoginResponse(Request $request, $user_not_active = fasle)
    {
        if ($user_not_active) {
            return response()->json(['status' => false, 'email' => 'Your account is not active.']);
        }
        return response()->json(['status' => false, 'email' => 'Incorrect login credentials.']);
    }
    
    0 讨论(0)
  • 2020-11-30 23:48

    Paste the following method to your LoginController.

    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => 'exists:users,' . $this->username() . ',active,1',
            'password' => 'required|string',
        ]);
    }
    

    The last two comma-separated parameters (active,1) act as a WHERE clause (WHERE active = '1') and can be alternatively written this way:

    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => Rule::exists('users')->where(function ($query) {
                $query->where('active', 1);
            }),
            'password' => 'required|string'
        ]);
    }
    

    Normally, the validation method only checks if email and password fields are filled out. With the modification above we require that a given email address is found in a DB row with active value set to 1.

    You can also customize the message:

    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => 'exists:users,' . $this->username() . ',active,1',
            'password' => 'required|string',
        ], [
            $this->username() . '.exists' => 'The selected email is invalid or the account has been disabled.'
        ]);
    }
    

    Note that the above message will be shown both when a given email address doesn't exist or when the account is disabled.

    0 讨论(0)
  • 2020-11-30 23:48

    I'm new to Laravel, and this is aimed at newcomers too. Long-timers feel free to tell me why this is bad practice, as I genuinely don't know any better yet.

    As at 24th August 2019 - using Laravel 5.8 - This is my personal implementation.

    Assumptions made:

    1. You started out using Artisan Make:Auth
    2. You've added 'active' as a bool (tinyInt) to your User table and updated the relevant Models etc...
    3. You're trying to prevent users from gaining access to your application via standard Auth, when: 'active' = 0.

    If this is the case, you can leave your LoginController alone.

    Instead open "Illuminate/Auth/Middleware/Authenticate.php" and replace the handle() method with:

    public function handle($request, Closure $next, ...$guards)
        {
            if(!$request->user()->active){
                // either abort with simple 403 access denied page
                // abort(403, "You don't have permissions to access this area");
    
                // OR force Logout and redirect back to the login page
                return redirect('login')->with($this->auth->logout());
            }
    
            $this->authenticate($request, $guards);
            return $next($request);
        }
    

    Note: Auth::logout() won't work here, but it's already pulled in via the constructor at the top of the file.

    public function __construct(Auth $auth)
        {
            $this->auth = $auth;
        }
    

    So you can just use $this->auth->logout(); instead.

    Thinking about it - You could very easily swap 'Active' for pretty much any criteria and update this middleware the very same way! Hope this helps!

    0 讨论(0)
  • 2020-11-30 23:51
      protected function sendLoginResponse(Request $request) {
      $request->session()->regenerate();
      $this->clearLoginAttempts($request);
      if ($response = $this->authenticated($request, $this->guard()->user())) {
          return $response;
      }
      $user = $this->guard()->user();
      if($user->is_active) {
        return $request->wantsJson() ? new JsonResponse([], 204) : redirect()->intended($this->redirectPath());
      } else {
        $request->session()->flush();
        return redirect()->route('login')->with('error', 'This account is not activated. Please contact the administrator.');
      }    
    }
    

    I put this function inside Auth\LoginController

    0 讨论(0)
提交回复
热议问题