在laravel中,一个账号可以多地方同时登录,有时候会存在一个问题,就是比如你修改密码后,这些都登录的人不会立即退出登录,还是登录状态。

如何让其他设备上的 Session 失效?

laravel为我们提供了方法,只是默认他是注释掉了。

Laravel 提供了让用户 Session 在除当前设备之外的其他登录设备上失效的机制,要实现这个功能,要将 Illuminate\Session\Middleware\AuthenticateSession 中间件在 app/Http/Kernel.php 类的 web 中间件组中的注释取消:

取消注释后,如果修改了用户密码,则此账号所有session都会失效。

当然,你也可以使用 Auth 门面上的 logoutOtherDevices 方法实现在其他设备「退出」,该方法要求用户提供登录密码:

use Illuminate\Support\Facades\Auth;

Auth::logoutOtherDevices($password);

但是如果你存在多个guard,不会发现, AuthenticateSession 会存在问题,不同的guard 在同一浏览器下登录,会互相挤掉。

查看 Illuminate\Session\Middleware\AuthenticateSession 的代码,你会发现,代码中没有区分guard,只用了一个session key “password_hash”。

因此,不同gurad 用户的password_hash不同,就会退出登录。

要解决这个问题,就需要自己重新 AuthenticateSession 部分代码。

1、在app\Http\Middleware目录下新建AuthenticateSession.php

2、类名 AuthenticateSession 继承 Illuminate\Session\Middleware\AuthenticateSession

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Auth\AuthenticationException;

class AuthenticateSession extends \Illuminate\Session\Middleware\AuthenticateSession
{
    public function getPasswordName()
    {
        $name = $this->auth->getName();
        return str_replace('login_', 'password_hash_', $name);
    }

    public function handle($request, Closure $next)
    {

        if (!$request->user() || !$request->session()) {
            return $next($request);
        }

        if ($this->auth->viaRemember()) {
            $passwordHash = explode('|', $request->cookies->get($this->auth->getRecallerName()))[2];

            if ($passwordHash != $request->user()->getAuthPassword()) {
                $this->logout($request);
            }
        }

        if (!$request->session()->has($this->getPasswordName())) {
            $this->storePasswordHashInSession($request);
        }

        if ($request->session()->get($this->getPasswordName()) !== $request->user()->getAuthPassword()) {
            $this->logout($request);
        }

        return tap($next($request), function () use ($request) {
            $this->storePasswordHashInSession($request);
        });
    }

    protected function logout($request)
    {
        $this->auth->logout();

        $request->session()->forget($this->auth->getName());
        $request->session()->forget($this->getPasswordName());

        throw new AuthenticationException;
    }


}

3、修改 app/Http/Kernel.php 类的 web 中间件组 ,添加我们自定义的中间件。

好了,现在多gurad下使用就没问题了。

发表评论

您的电子邮箱地址不会被公开。