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

Posted

技术标签:

【中文标题】Laravel - 在登录时销毁现有会话【英文标题】:Laravel - destroy existing sessions on login 【发布时间】:2014-10-23 19:26:29 【问题描述】:

有没有办法检查用户是否已经在另一台机器上拥有有效会话?

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

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

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

$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

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

谢谢!

【问题讨论】:

Laravel 没有对此的内置支持。登录/注销身份验证方法仅适用于当前会话。 您将无法使用它。它只会对您登录时保存在浏览器中的特定会话执行此操作。 可能想查看***.com/questions/5443355/… 我知道 Laravel 支持数据库会话,所以你可以做的是当用户登录时,检查该用户的表并销毁该 ID 的会话. 那是不幸的。生病签出该链接,但是我不希望转移到数据库会话,因为基于默认文件的会话似乎工作得很好。也许我会开发一些东西,可以在文件中找到用户会话,如果它们存在就销毁它们。但是每次用户登录时运行它可能会很昂贵。我们会看到。感谢所有 cmets。 阅读该链接后,我也许可以在用户登录时保留与用户关联的 session_id,然后当用户从新位置登录时,如链接所述,切换到旧会话,销毁它们,然后切换回/为这个最新位置创建一个新会话。假设 laravel 可以正常使用标准的 php 会话函数。 【参考方案1】:

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

    当注销事件被触发(auth.logout)时,你会清除它。

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

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

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

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

希望这会有所帮助!

【讨论】:

对于给定的用户模型,我必须将这个会话 ID 保存在数据库中,对吗?或者是否会从内存中检索现有的用户模型(我的理解是在页面加载后,内存中的用户对象将被破坏)。我已经转移到数据库会话,所以我将使用它,但我想了解这种方法。 是的,在此示例中,您必须将最后一个会话 ID 保存在用户模型中的数据库中。【参考方案2】:

希望你能看到这份工作:

Session::regenerate(true);

获得一个新的 session_id。

【讨论】:

【参考方案3】:

我意识到这是一个老问题,但现在 laravel 5.6 中有一个方法可以做到这一点,所以它可能对以后来的人有用。你也可以很容易地将此​​方法改装到早期版本的 laravel 中。

请参阅https://laravel.com/docs/5.6/authentication#invalidating-sessions-on-other-devices 上的文档

我的用例与您相同(在登录时注销所有其他设备)。我覆盖了默认登录方法以添加我自己的自定义逻辑(首先从 vendor/laravel/framework/src/illuminate/Foundation/Auth/AuthenticatesUsers.php 复制默认登录方法)

在该方法中,有一行 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);

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

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

较旧的 Laravel 版本

我实际上使用的是 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();

然后我把它复制到我的 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();

然后我可以在我的登录方法中调用此方法,正如我之前在回答中指定的那样,稍作调整 - $this->logoutOtherDevices($request->password);

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

【讨论】:

【参考方案4】:

这可能不是最好的答案,但我首先想到的是降低会话的超时时间。

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

我现在会尝试研究一下,看看其他人是否想出了更好的东西。

【讨论】:

这实际上是我的问题的原因所在。我们希望会话持续 1 周,而不是在浏览器关闭时销毁。因此,我们在 app->config->session.php 中进行了适当的设置以完成此操作。但是由于这个长期持续的会话,我希望我也能够完成我在问题中描述的内容,但事实似乎并非如此。

以上是关于Laravel - 在登录时销毁现有会话的主要内容,如果未能解决你的问题,请参考以下文章

在会话自动销毁之前调用自定义方法

远程销毁 php 中的会话(用户在其他地方登录)?

laravel - 在登录移动应用程序时保存会话凭据

如何正确启动和销毁会话?

如何在laravel 5.5中会话时自动重定向到登录页面

在JSP中销毁会话[关闭]