Laravel删除用户后多端会话重复检索已删除用户的解决方法
Laravel删除账号后其他端重复查询已删除用户的解决方法
Laravel默认的SessionGuard仅会缓存查询到的有效用户实例,当账号被删除后,user()方法每次调用都无法查到有效用户,也不会标记用户已不存在的状态,因此会重复执行数据库查询。
方案一:自定义Guard解决单次请求重复查询问题
通过重写SessionGuard的user()方法,增加用户不存在的标记,同时触发登出逻辑清空无效认证信息:
- 第一步:创建自定义Guard类
// 路径 app/Guards/SessionGuard.php <?php namespace App\Guards; use Illuminate\Auth\SessionGuard as BaseSessionGuard; class SessionGuard extends BaseSessionGuard { // 标记用户不存在,避免重复查询 protected $userNotFound = false; public function user() { // 已登出或已确认用户不存在,直接返回null if ($this->loggedOut || $this->userNotFound) { return null; } // 已有用户缓存直接返回 if (!is_null($this->user)) { return $this->user; } $id = $this->session->get($this->getName()); // 尝试从会话获取用户 if (!is_null($id) && $this->user = $this->provider->retrieveById($id)) { $this->fireAuthenticatedEvent($this->user); } // 会话没查到,尝试从记住我cookie获取 if (is_null($this->user) && !is_null($recaller = $this->recaller())) { $this->user = $this->userFromRecaller($recaller); if ($this->user) { $this->updateSession($this->user->getAuthIdentifier()); $this->fireLoginEvent($this->user, true); } } // 确认用户不存在,打标记并执行登出清空无效信息 if (is_null($this->user)) { $this->userNotFound = true; $this->logout(); } return $this->user; } }
- 第二步:注册自定义Guard驱动
在app/Providers/AuthServiceProvider.php的boot方法中添加驱动注册逻辑:
public function boot() { $this->registerPolicies(); \Auth::extend('custom_session', function ($app, $name, array $config) { $guard = new \App\Guards\SessionGuard( $name, $app['auth']->createUserProvider($config['provider']), $app['session.store'], $app['request'] ); if (method_exists($guard, 'setCookieJar')) { $guard->setCookieJar($app['cookie']); } if (method_exists($guard, 'setDispatcher')) { $guard->setDispatcher($app['events']); } if (method_exists($guard, 'setRequest')) { $guard->setRequest($app->refresh('request', $guard, 'setRequest')); } return $guard; }); }
- 第三步:修改认证配置使用自定义Guard
修改config/auth.php中的guards配置:
'guards' => [ 'web' => [ 'driver' => 'custom_session', 'provider' => 'users', ], ],
修改完成后,单次请求内首次查询到用户不存在就会打标记,后续调用auth()相关方法不会再重复查询,同时会自动清空当前会话和记住我cookie,用户后续访问不会再携带无效认证信息。
方案二:主动清理所有端会话
如果需要删除账号后立刻让所有端的会话失效,不需要等用户访问触发,可以选择以下方式:
- 若使用数据库存储会话:删除
sessions表中所有user_id为当前删除用户ID的记录即可 - 若使用Redis/文件存储会话:可以给用户表增加
session_version字段,登录时将版本号存入会话,每次认证时比对用户表的版本号和会话存储的版本号,删除用户时将版本号+1,所有旧会话就会自动失效 - 也可以遍历对应存储的所有会话,匹配对应用户ID后批量删除,适合会话量不大的场景
内容的提问来源于stack exchange,提问作者Tung Hoang
相关产品推荐
相关产品推荐

