Laravel多表JWT注销必须手动隔离黑名单,否则admin登出会误删user token;需为各表配独立guard/provider、模型注入guard标识、黑名单按guard分库存储、所有操作显式指定guard名。

多表 JWT 注销失效在 Laravel 中不能靠默认机制自动实现,必须手动隔离黑名单逻辑,否则 admin 登出可能误删 user 的 token,或刷新时 payload 混用导致越权。核心是让每个 guard(如 users、admins)拥有独立的黑名单存储空间,并在签发、校验、注销全流程中严格绑定 guard 上下文。
1. 为各用户表配置独立 guard 和 provider
在 config/auth.php 中新增 guard 与对应 provider:
'admin' => ['driver' => 'jwt', 'provider' => 'admins']'merchant' => ['driver' => 'jwt', 'provider' => 'merchants']- 对应 provider 需指定各自模型:
'admins' => ['driver' => 'eloquent', 'model' => App\Models\Admin::class]
2. 模型实现 JWTSubject 并注入 guard 标识
每个模型(User、Admin 等)必须实现 JWTSubject 接口,并在 getJWTCustomClaims() 中写入 guard 名:
return ['guard' => 'admin'];- 该字段将嵌入 JWT payload,后续用于黑名单 key 分片和中间件路由校验
3. 黑名单缓存按 guard 隔离
tymon/jwt-auth 默认使用全局 cache 实例,需通过服务容器绑定专用 Redis store:
- 在
config/cache.php中新增'jwt'缓存 store,连接独立 Redis 数据库(如 db=3) - 在
AppServiceProvider@register()中做上下文绑定: $this->app->when(Illuminate::class)->needs(Repository::class)->give(fn() => app('cache')->store('jwt'));
4. 注销与刷新操作显式指定 guard
所有涉及 token 生命周期的操作都必须带 guard 名,避免走默认:
- 登录:
Auth::guard('admin')->login($admin) - 注销:
Auth::guard('admin')->logout() - 刷新:
Auth::guard('admin')->refresh() - 中间件:
middleware('auth:admin'),不可简写为auth:api
5. 自定义黑名单添加逻辑(可选但推荐)
重写 Blacklist::add() 方法,在 cache key 中拼入 guard 前缀:
- 例如:key 格式为
blacklist:admin:{jti}或blacklist:merchant:{jti} - 从 payload 提取
$payload['guard']和$payload['jti']构建唯一键 - 设置过期时间等于 JWT 的
exp时间戳,确保自动清理
不复杂但容易忽略,关键就在 guard 名全程一致、黑名单存储物理隔离、以及 jti + guard 双因子标识。


















