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
Laravel - destroy existing sessions on login
提问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,以便:
When logout event is fired (auth.logout) you would clear it.
When new logging event is fired you can check if attribute session_id is not null within the user model.
If it's not - destroy previous session by:
当注销事件被触发 (auth.logout) 时,您将清除它。
当新的日志事件被触发时,您可以检查用户模型中的属性 session_id 是否不为空。
如果不是 - 通过以下方式销毁上一个会话:
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\AuthenticateSession
middleware 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.
我现在会尝试研究一下,看看其他人是否提出了更好的方法。