JWT 基础原理:结构、流程与无状态特性
JSON Web Token(JWT)是目前 SaaS 鉴权体系中最广泛使用的令牌格式。理解 JWT 的结构、生成验证流程及其无状态特性,是构建 Redis 缓存层之前必须掌握的核心基础。本节从三个维度展开:JWT 的物理结构、令牌的生命周期管理、以及无状态设计带来的架构收益与约束。
2.1 JWT 结构:三部分拆解
一个标准的 JWT 由三个 Base64URL 编码的片段组成,以英文句号 . 分隔:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.
POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29NSlwEi4uPC6Z6H5T4W5BixYwFjGqWfXw9X0f20sQ8G9Hw
| 部分 | 名称 | 内容示例 | 作用 |
|---|---|---|---|
| Header | 头部 | {"alg":"RS256","typ":"JWT"} |
声明签名算法与令牌类型 |
| Payload | 载荷 | {"sub":"1234567890","name":"John Doe","admin":true,"iat":1516239022} |
携带用户身份与自定义声明 |
| Signature | 签名 | Base64URL 编码的 HMAC/RSA/ECDSA 输出 | 防篡改、验证令牌来源 |
关键认知:Header 和 Payload 仅做 Base64URL 编码,不是加密。任何持有令牌的人都可以解码读取内容。敏感信息(如密码、手机号)严禁放入 Payload。
Header(头部)
Header 通常包含两个字段:
- alg:签名算法,常见值
HS256(HMAC-SHA256)、RS256(RSA-SHA256)、ES256(ECDSA-SHA256)。 - typ:令牌类型,固定为
JWT。
Payload(载荷)
Payload 包含三类声明(Claims):
| 声明类型 | 说明 | 常用字段 |
|---|---|---|
| 注册声明 | 预定义的标准字段 | iss(签发者)、sub(主题)、aud(受众)、exp(过期时间)、iat(签发时间) |
| 公共声明 | 公开定义的字段,需在 IANA 注册或使用 URI 命名 | https://api.example.com/role |
| 私有声明 | 服务间自定义字段 | tenant_id、permissions、session_id |
Signature(签名)
签名由以下公式生成:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
对于非对称算法(RS256/ES256),使用私钥签名、公钥验签。签名确保令牌在传输过程中未被篡改。
2.2 JWT 生成与验证流程
JWT 的生成与验证是两个对称但方向相反的过程。下面以 SaaS 登录场景为例,展示完整链路。
生成流程(签发令牌)
- 用户认证:客户端提交用户名/密码或 OAuth 授权码。
- 服务端校验:验证凭据有效性,查询用户角色与租户信息。
- 组装 Payload:填充
sub、exp、iat、tenant_id等声明。 - 计算签名:使用密钥对 Header.Payload 进行签名。
- 返回令牌:将完整 JWT 字符串返回给客户端。
验证流程(校验令牌)
- 解析令牌:按
.分割为三部分。 - 解码 Header:读取
alg字段,确定签名算法。 - 重新计算签名:使用本地密钥对 Header.Payload 计算签名。
- 比对签名:将计算结果与令牌携带的 Signature 对比。
- 校验声明:检查
exp(是否过期)、aud(受众是否匹配)、iss(签发者是否可信)。 - 提取身份:从 Payload 中获取用户 ID、角色等信息。
2.3 JWT 无状态特性
JWT 最核心的设计理念是无状态(Stateless)。服务端不需要维护会话存储,所有用户身份信息都编码在令牌本身。
| 对比维度 | 传统 Session 鉴权 | JWT 无状态鉴权 |
|---|---|---|
| 存储位置 | 服务端内存/Redis 存储 Session ID | 客户端持有完整令牌 |
| 扩展性 | 需要 Session 共享或粘性会话 | 任意节点均可验证,天然支持水平扩展 |
| 吊销能力 | 直接删除 Session 即可 | 需配合黑名单或短过期+刷新机制 |
| 网络开销 | 仅传输 Session ID(短字符串) | 传输完整 JWT(通常 500-2000 字节) |
| 服务端压力 | 每次请求需查询存储 | 仅需计算签名,无 I/O 开销 |
架构收益:在 SaaS 多租户场景中,无状态 JWT 允许鉴权服务完全无状态化,结合 Redis 缓存层可以实现“先本地验证、再缓存回退、最后数据库兜底”的三级加速链路。
无状态带来的挑战
- 令牌不可撤销:签发后无法主动失效,必须依赖
exp过期时间。 - Payload 大小膨胀:携带过多声明会增加每次请求的传输开销。
- 密钥管理复杂:非对称算法需要安全分发公钥,对称算法需要所有服务共享密钥。
- 无法感知用户状态变更:用户被禁用或角色变更后,已签发的 JWT 仍然有效。
实战建议:在 SaaS 系统中,JWT 的过期时间通常设置为 15-30 分钟,配合 Refresh Token 实现长期登录。对于需要即时吊销的场景(如用户退出、密码修改),使用 Redis 维护一个“黑名单”缓存,在验证 JWT 时先检查该令牌是否已被吊销。
无状态与 Redis 的互补关系
JWT 的无状态特性与 Redis 的有状态缓存并不矛盾,而是形成互补:
- JWT 负责身份验证:快速验证令牌合法性,无需查询数据库。
- Redis 负责会话状态:存储 Refresh Token、黑名单、用户权限快照等动态数据。
- 组合效果:JWT 减少 80% 的数据库查询,Redis 弥补 JWT 无法动态管理的短板。