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),使用私钥签名、公钥验签。签名确保令牌在传输过程中未被篡改。

JWT 三部分结构示意图 Header alg: "RS256" typ: "JWT" Payload sub: "user_123" exp: 1710000000 Signature HMACSHA256( header.payload, secret) 编码与签名关系 Header 和 Payload 仅做 Base64URL 编码(可解码读取) Signature 使用密钥对 header.payload 进行签名(防篡改) 最终令牌格式:Header.Payload.Signature

2.2 JWT 生成与验证流程

JWT 的生成与验证是两个对称但方向相反的过程。下面以 SaaS 登录场景为例,展示完整链路。

生成流程(签发令牌)

  1. 用户认证:客户端提交用户名/密码或 OAuth 授权码。
  2. 服务端校验:验证凭据有效性,查询用户角色与租户信息。
  3. 组装 Payload:填充 sub、exp、iat、tenant_id 等声明。
  4. 计算签名:使用密钥对 Header.Payload 进行签名。
  5. 返回令牌:将完整 JWT 字符串返回给客户端。

验证流程(校验令牌)

  1. 解析令牌:按 . 分割为三部分。
  2. 解码 Header:读取 alg 字段,确定签名算法。
  3. 重新计算签名:使用本地密钥对 Header.Payload 计算签名。
  4. 比对签名:将计算结果与令牌携带的 Signature 对比。
  5. 校验声明:检查 exp(是否过期)、aud(受众是否匹配)、iss(签发者是否可信)。
  6. 提取身份:从 Payload 中获取用户 ID、角色等信息。
JWT 生成与验证流程 生成流程(签发) ① 用户认证(用户名/密码) ② 服务端校验凭据 ③ 组装 Payload 声明 ④ 使用密钥计算签名 ⑤ 返回 JWT 给客户端 验证流程(校验) ① 解析令牌(按 . 分割) ② 读取 Header 中的算法 ③ 重新计算签名并比对 ④ 校验 exp/aud/iss 声明 ⑤ 提取用户身份信息

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 无法动态管理的短板。