JWT如何避免多端登录

问题背景​

​目前在做的游戏项目,使用了HTTP短连接网关,登录鉴权方式则选择了 JWT 。得益于JWT的无状态特性,Gate网关可以非常容易地分布式部署/水平扩展,但存在多端登录的问题。

  • ​需求​​:单账号仅允许​​最后登录设备​​保持在线,旧设备需被踢下线。
  • ​挑战​​:JWT无状态特性无法主动失效旧Token,需额外机制实现账号互斥登录。

解决方案

​比较容易想到维护一个字典 /映射 ,key为account,value为 jwt token,一个account始终只对应它最新签发的jwt token,gate就根据这个字典判断当前请求是否为该账号最新登录的用户,如果是,则正常处理消息,否则返回特定错误码,客户端收到错误码后弹窗提示”该账号已在其他设备登录“。而关于这个字典的存储,又有两种方案。

1 . Redis缓存

2. 所有Gate同步进程内缓存(每个Gate的本地缓存都有一份相同的字典)

方案对比:Redis缓存 vs 进程内缓存同步​

​维度​​Redis方案​​进程内缓存同步​
​数据一致性​​强一致性​​(所有节点读取同一Redis实例)​最终一致性​​(同步延迟可能导致短暂不一致)
​扩展性​✅ 新增节点无需同步,直连Redis即可❌ 新节点需全量同步数据,规模大时开销高
​故障恢复​✅ 数据持久化,重启后不丢失❌ 节点宕机导致部分缓存丢失,需重新同步
​实现复杂度​✅ 简单(依赖Redis原子操作,如SET+EXPIRE❌ 复杂(需实现分布式同步协议,如Gossip)
​性能​⚠️ 依赖Redis吞吐量(需集群优化)✅ 本地读取速度快,但同步有网络开销
​外部依赖​❌ 需维护Redis高可用集群✅ 无外部依赖,纯逻辑实现

​关键设计细节​

  1. ​Token有效性校验​
    • ​流程​​:客户端请求携带Token → Gateway校验JWT签名 → 查询Redis/缓存中该账号的​​最新Token​​ → 匹配则放行,否则返回401-Kicked错误码。
    • ​优化​​:Token生成时附加​​递增版本号​​(如时间戳),减少内存占用(仅存储版本号而非完整Token)。
  2. ​登录互斥逻辑​
    • ​登录时​​:更新账号对应Token至Redis/广播同步到所有节点,旧Token立即失效。
    • ​客户端响应​​:旧设备收到401-Kicked时,客户端提示“账号异地登录”并跳转至登录页。
  3. ​容灾与降级​
    • ​Redis方案​​:需部署Redis哨兵/集群,避免单点故障;故障时可短暂降级为允许多设备登录(牺牲安全性保可用性)。
    • ​进程内缓存​​:需设计数据恢复机制(如节点重启后从其他节点拉取全量数据)。

最后选择了Redis缓存作为落地方案。

滚动至顶部