3. 鉴权基础:从 Session 到 JWT 的演进、Token 的结构与生命周期管理、常见鉴权漏洞

在多租户 SaaS 架构中,鉴权(Authentication)是拦截链路的第一道关卡。本章从传统 Session 鉴权的瓶颈出发,分析 JWT 的演进动因、Token 结构设计与生命周期管理策略,并梳理常见鉴权漏洞及其防护要点。

3.1 从 Session 到 JWT:鉴权模型的演进

传统单体应用广泛采用 Session-Cookie 鉴权模式:用户登录后,服务端创建 Session 并返回 Session ID 写入 Cookie;后续请求携带 Cookie,服务端查询内存或 Redis 中的 Session 数据完成身份识别。

对比维度 Session 鉴权 JWT 鉴权
状态存储 服务端存储(内存/Redis) 客户端存储(Token 自包含)
扩展性 需共享 Session 存储(粘性 Session / 集中缓存) 无状态,任意节点均可验证
跨域支持 受 Cookie 同源策略限制 通过 Authorization 头,天然跨域
性能开销 每次请求需查询存储 本地解析验证,无远程 I/O
多租户隔离 需额外设计租户上下文绑定 Token 内嵌租户标识,天然隔离

演进动因:微服务化与多租户 SaaS 要求鉴权层无状态、可水平扩展、支持跨服务传递用户身份。JWT(JSON Web Token)通过自包含的声明结构,将用户身份与权限信息编码进 Token,服务端只需验证签名即可信任 Token 内容,无需回查存储。

Session 与 JWT 鉴权流程对比 Session 鉴权流程 客户端 服务端 Session Redis / 内存 每次请求查存储 有状态,难水平扩展 JWT 鉴权流程 客户端 JWT 验证 签名密钥 本地解析,无远程 I/O 无状态,天然可扩展

3.2 Token 的结构与生命周期管理

3.2.1 JWT 的结构

JWT 由三个 Base64URL 编码的部分组成,以点号(.)分隔:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
部分 内容 示例字段
Header 签名算法 & Token 类型 {"alg":"HS256","typ":"JWT"}
Payload 声明(Claims):用户身份、租户 ID、角色、过期时间等 {"sub":"user_001","tenant":"acme","role":"admin","exp":1710000000}
Signature 对 Header + Payload 的签名,防止篡改 HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

多租户最佳实践:在 Payload 中显式声明 tenant_id 字段,鉴权拦截器解析后注入请求上下文,实现租户级数据隔离。避免将敏感信息(如密码、完整手机号)放入 Payload,因为 Payload 仅 Base64 编码,并非加密。

3.2.2 Token 生命周期管理

JWT 的无状态特性带来便利,但也使 Token 撤销变得困难。合理的生命周期管理策略是鉴权安全的关键:

  1. 短期 Access Token + 长期 Refresh Token:Access Token 有效期短(15~30 分钟),Refresh Token 有效期长(7~30 天),通过 Refresh Token 轮换获取新 Access Token。
  2. Token 黑名单(Deny List):在 Redis 中维护已撤销 Token 的 jti(JWT ID)列表,拦截器每次验证时检查黑名单。
  3. Token 轮换(Rotation):每次使用 Refresh Token 时,同时下发新的 Refresh Token,旧 Refresh Token 立即失效。
  4. 绝对过期与滑动过期:Access Token 设置绝对过期时间;Refresh Token 可设置滑动过期(每次使用刷新有效期)。
Token 生命周期与刷新流程 Access Token + Refresh Token 生命周期 客户端 鉴权服务 ① 登录请求 ② 下发 AT + RT ③ 携带 AT 请求资源 AT 过期 ⑤ 使用 RT 刷新 ⑥ 下发新 AT + 新 RT Redis 黑名单 校验 jti

3.3 常见鉴权漏洞与防护

漏洞类型 攻击方式 防护措施
Token 泄露 XSS 窃取 LocalStorage 中的 Token;中间人攻击截获 Token 使用 HttpOnly Cookie 存储 Token;强制 HTTPS;设置短有效期
签名算法混淆 攻击者将 alg 改为 none 或对称算法,伪造 Token 服务端强制校验 alg 白名单;拒绝 none 算法
重放攻击 截获合法 Token 后重复使用 引入 jti + 一次性使用;结合时间戳与 nonce
弱密钥 使用简单密钥,被暴力破解签名 使用 256 位以上随机密钥;定期轮换密钥
Token 未过期 Token 永久有效,泄露后长期可用 设置合理的 exp 声明;实现 Refresh Token 轮换
越权访问 Token 中未校验租户 ID,A 租户用户访问 B 租户数据 Token 内嵌 tenant_id;拦截器强制校验租户归属

多租户鉴权红线:Token 中的 tenant_id 必须在签发时绑定,且不允许客户端修改。拦截器在解析 Token 后,需将 tenant_id 与请求路径/参数中的租户标识进行比对,防止租户越权。任何绕过租户校验的鉴权实现,都可能导致严重的数据泄露事故。

3.4 多租户 SaaS 鉴权拦截链路设计要点

  • 无状态优先:优先采用 JWT 自包含鉴权,减少对集中缓存的依赖,降低拦截链路延迟。
  • 租户上下文传递:在 Token Payload 中声明 tenant_id、role、permissions,拦截器解析后注入 ThreadLocal 或请求上下文。
  • 分层校验:网关层校验 Token 签名与过期时间;业务层校验租户权限与资源归属。
  • 黑名单缓存:对已撤销 Token 的 jti 使用 Redis 缓存,设置与 Token 过期时间一致的 TTL,避免内存泄漏。
  • 性能监控:对鉴权拦截链路增加耗时埋点,监控 P99 延迟,及时发现签名验证或黑名单查询的性能瓶颈。