Laravel - destroy existing sessions on login

后端 未结 4 1054
臣服心动
臣服心动 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 hope you will see this job:

    Session::regenerate(true);
    

    a new session_id be obtained.

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2021-01-14 15:48

    This may not be the best answer, but first thing that came to my mind was lowering the timeout on the session.

    In app->config->session.php there's a setting for both lifetime and expire_on_close (browser).

    I'd try looking into that for now, and see if someone else comes up with something better.

    0 讨论(0)
  • 2021-01-14 15:49

    You can save a session_id within a user model, so that:

    1. When logout event is fired (auth.logout) you would clear it.

    2. When new logging event is fired you can check if attribute session_id is not null within the user model.

    3. If it's not - destroy previous session by:

    Session::getHandler()->destroy( $user->session_id );

    $user->session_id = Session::getId();

    Hope that would help!

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