JWT多用户刷新令牌在Laravel中真正兼容的关键是按guard隔离刷新逻辑:路由需明确指定middleware('auth:admin')等,中间件须动态获取guard并调用对应Auth::guard($guard)->refresh(),黑名单和响应头也须按guard切片,前端需同步维护guard上下文。

JWT多用户刷新令牌在Laravel中要真正兼容,关键不是“写一个通用中间件”,而是让刷新逻辑能识别当前请求属于哪个用户类型(如 user、admin、merchant),并严格按对应 guard 执行签发、校验和黑名单操作。否则 admin 刷新时可能误删 user 的 token,或返回错误的用户实例。
中间件必须显式绑定 guard 名称
不能只写 middleware('auth:api') 或泛用 jwt.auth。每个用户类型需独立中间件或带参数的统一中间件:
- 路由中明确指定 guard:
middleware('auth:admin')或middleware('auth:merchant') - 若用自定义刷新中间件(如
RefreshToken),内部必须通过$request->route()或请求头提取 guard 上下文,再调用Auth::guard($guard)->refresh() - 避免硬编码
Auth::guard('api')—— 这会强制所有请求走同一套逻辑,破坏多表隔离
刷新前必须完成 guard 级别认证
刷新不是无条件行为,它依赖当前 token 已通过对应 guard 的基础校验:
- 中间件中先执行
$this->auth->parseToken()->authenticate(),确保 token 有效且归属正确 guard - 若使用
onceUsingId(),ID 必须来自当前 guard 的 model(例如 admin 表主键),不能直接取 payload['sub'] 后无区分地调用Auth::guard('api')->onceUsingId() - 推荐方式:从 payload 中读取自定义 claim(如
'guard' => 'admin'),再动态调用Auth::guard($payload['guard'])->onceUsingId(...)
黑名单与响应头必须按 guard 隔离
默认 tymon/jwt-auth 的黑名单是全局单例,不感知 guard。多用户场景下必须切片:
- 重写
getJWTCustomClaims(),在每个模型中加入'guard' => 'admin'等标识 - 自定义
JWTBlacklist实现,在add()和remove()方法中用$payload['guard']拼接缓存 key 或数据库字段前缀(如blacklist:admin:abc123) - 刷新成功后,
setAuthenticationHeader()返回的 token 必须携带相同 guard 标识,前端才能正确存储和后续携带
前端配合不可少
后端做了隔离,前端也要匹配,否则刷新后的 token 仍被当作 user 使用:
- 登录成功后,除保存 token 外,也应记录当前 guard 类型(如 localStorage.setItem('auth_guard', 'admin'))
- 每次请求自动在 Authorization 头中携带 token,并在请求头加
X-Auth-Guard: admin作为辅助判断(可选但推荐) - 刷新接口响应里,除了新 token,最好也返回
{"guard": "admin"},便于前端校验上下文一致性


















