JWT Token 机制设计演进:从单 Token 到企业级认证体系

现在的大部分 Web 系统、App、后台管理系统,认证方案几乎都绕不开 JWT(JSON Web Token)。

但很多项目一开始只会:

  • 登录 → 发一个 Token
  • 请求 → 校验 Token

随着系统复杂度增加,很快就会遇到:

  • 用户退出后 Token 还能用
  • 修改密码无法让旧 Token 失效
  • 无法单设备踢人
  • 无法强制下线
  • Redis 压力过大
  • 无法做到真正的"无状态"

于是 Token 机制会不断演进。

本文从简单到复杂,梳理一套完整的 Token 体系设计。


一、单 Token

最简单的方案:

用户登录成功后,服务器签发一个 JWT:

json 复制代码
{
  "user_id": 1001,
  "exp": 1710000000
}

客户端之后每次请求:

http 复制代码
Authorization: Bearer xxx

服务端:

  1. 校验 JWT 签名
  2. 校验 exp
  3. 解析 user_id

即可完成认证。


优点

1. 完全无状态

服务端不存储 Token。

天然适合:

  • 微服务
  • 分布式
  • 多实例部署

2. 性能极高

只需要:

  • JWT 解密
  • HMAC/RSA 验签

无需查 Redis。


3. 实现极其简单

适合:

  • 小项目
  • Demo
  • 内网系统

缺点

这是它最大的致命问题:

Token 一旦签发,在过期前永远有效。

即:

  • 用户退出登录 → Token 还能继续用
  • 修改密码 → 旧 Token 还能继续用
  • 用户被封禁 → Token 还能继续用
  • Token 泄露 → 无法立即失效

因此:

单 JWT 本质上无法"主动失效"。


二、单 Token + Redis 黑名单

为了解决 JWT 无法主动失效的问题。

开始引入:

Redis BlackList

退出登录时:

text 复制代码
blacklist:token_xxx -> exp

请求时:

text 复制代码
1. 校验 JWT
2. 查询 Redis 是否在黑名单

如果存在:

text 复制代码
Token 已失效

优点

解决了:

  • 登出立即失效
  • 管理员强制下线
  • Token 泄露后紧急封禁

缺点

1. Redis 压力增加

每次请求都需要:

text 复制代码
Redis GET

高并发下压力明显。


2. Token 越多黑名单越大

尤其:

  • 长时间 Token
  • 海量用户

Redis 会不断增长。


3. 仍然只有一个 Token

用户频繁登录:

  • Token 频繁过期
  • 用户体验差

于是:

双 Token 体系开始出现。


三、双 Token(AT + RT)

现代 Web 系统最主流方案。


核心思想

拆成:

Access Token(AT)

短期有效:

text 复制代码
15分钟

用于:

text 复制代码
接口访问

Refresh Token(RT)

长期有效:

text 复制代码
7天 / 30天

用于:

text 复制代码
刷新 Access Token

登录流程

登录成功:

服务端签发:

text 复制代码
AT(15分钟)
RT(7天)

请求流程

普通接口:

text 复制代码
携带 AT

AT 过期:

text 复制代码
使用 RT 换新 AT

优点

1. 安全性提升

即使:

text 复制代码
AT 泄露

攻击窗口也只有:

text 复制代码
15分钟

2. 用户体验好

用户无需频繁登录。


3. 适合移动端

App 可以长期在线。


缺点

仍然存在:

  • 修改密码无法让旧 Token 失效
  • 封禁用户无法立即失效

于是继续升级。


四、双 Token + token_version

这是很多中大型系统真正实用的方案。


核心思想

在数据库维护:

sql 复制代码
token_version

用户表:

sql 复制代码
users
├── id
├── password
├── token_version

签发 Token

AT:

json 复制代码
{
  "user_id": 1001,
  "token_version": 3,
  "exp": 1710000000
}

RT:

json 复制代码
{
  "user_id": 1001,
  "token_version": 3,
  "jti": "uuid",
  "exp": 1710000000
}

请求时

服务端:

text 复制代码
1. 校验 JWT
2. 查询用户 token_version
3. 对比 JWT 中的 token_version

不一致:

text 复制代码
Token 已失效

为什么强大?

因为:

可以让某个用户的所有 Token 瞬间全部失效。


修改密码

sql 复制代码
token_version++

效果:

  • 所有设备掉线
  • 所有 Token 作废

封禁用户

sql 复制代码
token_version++

效果:

  • 全平台强制下线

这是"用户级失效"

特点:

text 复制代码
粒度:用户级

即:

text 复制代码
让某用户所有 Token 全失效

缺点

1. 每次请求都需要查数据库

解决办法:

放 Redis:

text 复制代码
user_token_version:1001 -> 3

2. 无法单设备踢下线

因为:

text 复制代码
token_version 是用户级

只能:

text 复制代码
全设备失效

五、双 Token + Redis 黑名单

这是很多项目开始"半状态化"的阶段。


为什么还要黑名单?

因为:

token_version 无法解决"单 Token 立即失效"。

比如:

用户主动退出登录:

你总不能:

sql 复制代码
token_version++

否则:

text 复制代码
所有设备全掉

所以:

退出登录时:

text 复制代码
把当前 AT 加入 Redis 黑名单

适用场景

登出

text 复制代码
AT 拉黑

单 Token 风控

比如:

text 复制代码
检测到异常 IP

拉黑当前 Token。


缺点

仍然无法:

text 复制代码
单设备 AT 即时踢出

因为:

AT 本身无状态。


六、双 Token + token_version + Redis 黑名单 + AT 映射表

这已经接近大型系统方案。


核心目标

实现:

单设备即时踢下线


核心设计

登录成功后:

text 复制代码
user_at:1001:deviceA -> at_jti
user_at:1001:deviceB -> at_jti

或者:

text 复制代码
at_mapping:{jti} -> user/device

请求时

除了:

  • JWT 校验
  • token_version 校验
  • 黑名单校验

还需要:

text 复制代码
校验当前 AT 是否仍然是最新映射

为什么需要它?

比如:

用户在新设备登录。

你希望:

text 复制代码
旧设备立即下线

那么:

text 复制代码
覆盖 Redis AT 映射

旧 Token 立刻失效。


这是"设备级失效"

粒度:

text 复制代码
单设备

七、推荐方案

对于普通中大型项目。

我更推荐:

双 Token + token_version + RT 白名单

而不是:

text 复制代码
AT 映射表

为什么?

因为:

AT 应该尽量无状态

AT 生命周期很短:

text 复制代码
15分钟

没必要强行维护状态。

否则:

JWT 就退化成 Session 了。


推荐实践

AT(Access Token)

特点:

  • 短期
  • 无状态
  • 不存 Redis

内容:

json 复制代码
{
  "user_id": 1001,
  "token_version": 3,
  "exp": 1710000000
}

有效期:

text 复制代码
15分钟

RT(Refresh Token)

特点:

  • 长期
  • 有状态
  • 存 Redis

Redis:

text 复制代码
refresh_token:{jti}

内容:

json 复制代码
{
  "user_id": 1001,
  "token_version": 3,
  "jti": "uuid"
}

有效期:

text 复制代码
7天

刷新流程

刷新时:

text 复制代码
1. 校验 RT
2. 校验 Redis 中 jti
3. 删除旧 RT
4. 签发新 RT
5. 签发新 AT

这叫:

Refresh Token Rotation(RT轮换)

安全性远高于固定 RT。


八、各种方案对比

方案 能主动失效 单设备踢出 全设备失效 Redis压力 安全性
单 Token
单 Token + 黑名单
双 Token 部分
双 Token + token_version
双 Token + 黑名单 部分
双 Token + AT映射 很高

九、最终建议

小项目

推荐:

双 Token

简单够用。


中大型项目

推荐:

双 Token + token_version + RT轮换

这是性价比最高的方案。


强安全后台 / 金融系统

推荐:

双 Token + token_version + RT轮换 + 黑名单

必要时:

  • 设备管理
  • 单设备踢下线
  • 风控系统
  • IP 风险识别

十、核心认知

很多人误以为:

JWT = 无状态认证

实际上:

真正的大型系统几乎都是"半状态 JWT"

原因很简单:

你永远需要"主动失效能力"。

而:

text 复制代码
完全无状态

与:

text 复制代码
主动失效

天然冲突。

所以最终:

现代认证体系本质上都是:

"JWT + Redis状态控制"

只是:

状态维护到什么程度的问题。

相关推荐
掘金码甲哥7 小时前
哈哈哈哈哈打不过我吧,没有办法我(vllm)就是这么强大!
后端
invicinble8 小时前
spring事务相关信息量的沉淀
java·后端·spring
xlq223228 小时前
59.HTTP
网络·网络协议·http
jieyucx9 小时前
从基础语法到面向对象:Go语言如何实现封装、继承与多态?
开发语言·后端·golang
神奇小汤圆9 小时前
Spring Boot 3.2 + JDK 21 虚拟线程压测:传统线程池与 Project Loom 的吞吐量对比实践
后端
SuperArc19999 小时前
jar包文件修改(java编译与反编译)
java·开发语言·后端·jar·反编译
羡寒.9 小时前
接口突然变慢,你怎么排查?
java·后端·spring
ltlovezh9 小时前
AAC 元数据:ADTS 与 ASC 的区别、转换和常见坑
后端·ffmpeg·音视频开发
金銀銅鐵10 小时前
[Java] 自己写程序,来解析字段的 descriptor
java·后端