Laravel - 在登录时销毁现有会话

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25574114/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 10:01:26  来源:igfitidea点击:

Laravel - destroy existing sessions on login

phpsessionauthenticationlaravel

提问by Vigs

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 may already have, so that if they forget to logout from a computer say on campus or at work, and then they log in at home, it will destroy those other 2 sessions so they are no longer logged in?

我想要做的是当用户登录时,销毁他们可能已经拥有的其他会话,这样如果他们忘记从校园或工作中的计算机注销,然后他们在家中登录,它就会销毁其他 2 个会话因此它们不再登录?

Facebook employs this in some way.

Facebook 以某种方式使用了这一点。

My only thoughts so far is something to this effect:

到目前为止,我唯一的想法是这样的:

$user = User::find(1); // find the user
Auth::login($user); // log them in 
Auth::logout(); // log them out hoping that it will destroy all their sessions on all machines
Auth::login($user); // log them in again so they have a valid session on this machine

I have not had the chance to test this, and I do not know if Auth::login($user);will destroy all sessions for that user, or only the current one.

我还没有机会对此进行测试,我不知道是否Auth::login($user);会销毁该用户的所有会话,还是仅销毁当前会话。

Thanks!

谢谢!

回答by technik

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

您可以在用户模型中保存 session_id,以便:

  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:

  1. 当注销事件被触发 (auth.logout) 时,您将清除它。

  2. 当新的日志事件被触发时,您可以检查用户模型中的属性 session_id 是否不为空。

  3. 如果不是 - 通过以下方式销毁上一个会话:

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

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

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

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

Hope that would help!

希望这会有所帮助!

回答by ilhan g?ksel

I hope you will see this job:

我希望你会看到这份工作:

Session::regenerate(true);

a new session_id be obtained.

获得一个新的 session_id。

回答by Roxy Walsh

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.

我意识到这是一个老问题,但现在 laravel 5.6 中有一种方法可以做到这一点,所以它可能对稍后讨论这个问题的人有用。您还可以非常轻松地将此方法改装到早期版本的 laravel 中。

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

请参阅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)

我和你有同样的用例(登录时注销所有其他设备)。我覆盖了默认登录方法来添加我自己的自定义逻辑(首先从 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))- 在此中,在 return 语句之前,添加您对 logoutOtherDevices 的调用,如下所示

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\AuthenticateSessionmiddleware in your app/Http/Kernel.php, as per the docs

还要确保您已Illuminate\Session\Middleware\AuthenticateSession根据文档取消注释app/Http/Kernel.php 中的中间件

(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.

(请注意,我没有测试上面的代码,因为我使用的是没有这种方法的旧版 laravel,见下文)。不过,这应该适用于 5.6。

Older Laravel versions

较旧的 Laravel 版本

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

我实际上使用的是 laravel 5.5,所以无法使用这个方便的方法。幸运的是,它很容易添加。我打开了一个 laravel 5.6 项目,并从 vendor/laravel/framework/src/illuminate/Auth/SessionGuard.php 复制了 logoutOtherDevices 方法 - 作为参考,我粘贴在下面

/**
 * 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())

然后我将它复制到我的 LoginController 中——它可以放在你选择的其他地方,但我把它放在这里是为了方便/懒惰。我不得不稍微修改一下,如下($this->user()变成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);

然后,我可以在我的登录方法中调用此方法,如我在前面的回答中所指定的,稍作调整 - $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.

如果您想在本地进行测试,如果您在正常和隐身窗口中打开您的网站,它似乎可以工作。当您登录一个时,您将在另一个上注销 - 尽管您必须刷新才能看到任何更改。

回答by Tim Lewis

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).

在 app->config->session.php 中有生命周期和 expire_on_close(浏览器)的设置。

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

我现在会尝试研究一下,看看其他人是否提出了更好的方法。