实现 JWT 单点登录互踢机制的核心是在服务端维护登录状态版本,通常使用 Redis 存储用户 ID 对应的 token 版本号或唯一标识。每次请求时中间件比对 JWT 中的版本与 Redis 中的版本,不一致则拒绝访问。风险边界在于 Redis 不可用时会导致认证服务不可用,需评估依赖风险。
先说结论:JWT 本身无状态,实现互踢必须引入服务端状态存储,推荐 Redis 版本号方案。
- 适合:需要严格单点登录、允许依赖缓存中间件的业务场景
- 优先做:在 JWT payload 中增加版本字段,登录时递增 Redis 中的版本值
- 再验证:多设备同时登录,旧设备请求接口应返回 401 或 403
快速处理思路
无需复杂命令,重点在于代码逻辑调整。登录成功后生成 JWT 时将当前 Redis 版本号写入 token,请求中间件读取 token 版本号并与 Redis 实时比对。
为什么会这样
JWT 设计初衷是无状态验证,服务端不保存 token 信息,因此默认无法主动失效已发 token。实现互踢必须打破无状态限制,通过外部存储记录最新有效 token 特征。
分步处理
第一步:设计 JWT payload,增加ver字段存储版本号或jti存储唯一 ID。
第二步:建立 Redis Key 结构,例如auth:uid:{user_id}:version,初始值为 1。
第三步:修改登录接口,用户登录成功后递增 Redis 版本号,并将新版本号写入新生成的 JWT。
第四步:编写认证中间件,解析 JWT 获取版本号,查询 Redis 对应 Key,两者不一致则判定 token 失效。
怎么验证是否生效
使用设备 A 登录获取 Token A,再使用设备 B 登录同一账号获取 Token B。使用 Token A 请求受保护接口,服务端应返回 401 Unauthorized 或自定义互踢状态码。
常见坑
Redis 集群故障可能导致所有用户无法登录,需准备降级方案或本地缓存兜底。登录并发高时版本号递增可能出现竞争条件,需使用 Redis 原子操作INCR。
常见问题
不使用 Redis 能实现互踢吗?
不能。不引入服务端状态存储无法感知新登录行为,除非缩短 token 有效期牺牲用户体验。
用户主动 logout 需要处理吗?
需要。主动 logout 应清除 Redis 中的版本记录或将版本号标记为无效,防止旧 token 继续使用。