Laravel - destroy existing sessions on login

后端 未结 4 1057
臣服心动
臣服心动 2021-01-14 15:14

Is there a way to check if a user already has a valid session on a different machine?

What I want to do is when a user logs in, destroy an other sessions which they

4条回答
  •  我在风中等你
    2021-01-14 15:39

    I realise this is an old question, but there is now a method in laravel 5.6 that does exactly this, so it may be useful for someone coming to this later. You can also retro-fit this method to earlier versions of laravel very easily.

    See the docs at https://laravel.com/docs/5.6/authentication#invalidating-sessions-on-other-devices

    I had the same use case as you (log out all other devices on log-in). I overrode the default login method to add my own custom logic (first copying the default login method from vendor/laravel/framework/src/illuminate/Foundation/Auth/AuthenticatesUsers.php)

    In that method, there is the line if ($this->attemptLogin($request)) - within this, before the return statement, add your call to logoutOtherDevices, as below

    if ($this->attemptLogin($request)) {
    
            //log out all other sessions
            Auth::logoutOtherDevices($request->password); //add this line
    
            return $this->sendLoginResponse($request);
    }
    

    Also ensure you have un-commented the Illuminate\Session\Middleware\AuthenticateSession middleware in your app/Http/Kernel.php, as per the docs

    (note that I haven't tested the above code as I was using an older version of laravel that doesn't have this method, see below). This should work in 5.6 though.

    Older Laravel versions

    I was actually using laravel 5.5, so didn't have access to this handy method. Luckily, it's easy to add. I opened a laravel 5.6 project and copied the logoutOtherDevices method from vendor/laravel/framework/src/illuminate/Auth/SessionGuard.php - for reference I have pasted below

    /**
     * Invalidate other sessions for the current user.
     *
     * The application must be using the AuthenticateSession middleware.
     *
     * @param  string  $password
     * @param  string  $attribute
     * @return null|bool
     */
    public function logoutOtherDevices($password, $attribute = 'password')
    {
        if (! $this->user()) {
            return;
        }
    
        return tap($this->user()->forceFill([
            $attribute => Hash::make($password),
        ]))->save();
    }
    

    I then copied this into my LoginController - it could go somewhere else of your choice, but I've put it here for ease / laziness. I had to modify it slightly, as below ($this->user() becomes Auth::user())

     /**
     * Invalidate other sessions for the current user.
     * Method from laravel 5.6 copied to here
     *
     * The application must be using the AuthenticateSession middleware.
     *
     * @param  string  $password
     * @param  string  $attribute
     * @return null|bool
     */
    public function logoutOtherDevices($password, $attribute = 'password')
    {
        if (! Auth::user()) {
            return;
        }
    
        return tap(Auth::user()->forceFill([
            $attribute => Hash::make($password),
        ]))->save();
    }
    

    I can then call this method in my login method, as specified earlier in my answer, with a slight adjustment - $this->logoutOtherDevices($request->password);

    If you want to test this locally, it seems to work if you open your site on a normal and an incognito window. When you log in on one, you'll be logged out on the other - though you'll have to refresh to see anything change.

提交回复
热议问题