JWT 结构深度解析,签名算法:非对称加密 RS256 / 对称加密 HS256 的区别?

在使用 JWT(JSON Web Token)进行身份认证时,很多同学有很多问题:

  • JWT 到底是一个什么?构造是怎么样的?
  • 加密算法,RS256 / HS256 有什么区别?
  • 验签到底在验什么?
  • exp 过期是怎么判断的?
  • Token 过期与失效机制 是怎么样的?

本文将从 原理 → 实现 → 安全 → 实战设计 的角度,系统性地把这两个问题讲清楚。


一、JWT 的基本结构回顾

一个标准的 JWT 由三部分组成:

header.payload.signature
------------------------------
eyJhbGciOiJ9.eyJzdWIiOjM5MDIyfQ.SflKxwRJJf36POssw5c
  • Header(头部):声明使用的算法(如 RS256 / HS256)
  • Payload(载荷):业务数据(用户信息、过期时间等)
  • Signature(签名):防篡改签名(安全核心)
  • Header
    作用:描述令牌的元数据和签名算法。
    内容:通常包含令牌类型(typ: “JWT”)和签名算法(alg,如 HS256、RS256)。
    存储形式:一个 JSON 对象,经过 Base64Url​ 编码后形成第一部分。
    示例解码后:
{
  "alg": "HS256",
  "typ": "JWT"
}
  • Payload
    作用:包含实际的声明(claims),即要传递的信息。
    内容:
    1.预定义声明:标准字段,如 iss(签发者)、exp(过期时间)、sub(主题)等。
    2.公共声明:可以自定义的字段,但为了避免冲突,应使用已定义的名字或在名字中包含唯一标识符。
    3.私有声明:在双方约定下自定义的字段,用于交换信息。
    存储形式:一个 JSON 对象,经过 Base64Url​ 编码后形成第二部分。
    示例解码后:
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
  • Signature
    作用:验证令牌的真实性和完整性,防止数据被篡改。这是 JWT 安全性的核心。
    生成方式:将编码后的 Header 和 Payload 用 . 连接起来,然后使用 Header 中指定的算法和一个密钥(secret)进行签名。
公式(以 HS256 为例):
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

验证方式:服务器收到 Token 后,会用同样的密钥(如果是非对称加密,使用的是公钥)和算法重新计算签名,并与 Token 中的第三部分进行比较。如果一致,说明 Token 未被篡改;如果不一致或签名验证失败,则 Token 无效。

其中:

  • Base64Url 编码 ≠ 加密:Header 和 Payload 只是进行了编码,任何人都可以解码并查看其内容。因此,绝对不要在 Payload 中存放敏感信息(如密码)。
  • 签名是关键:虽然内容可见,但由于有签名的存在,任何对 Header 或 Payload 的修改都会导致签名验证失败,从而使 Token 作废。
  • 所以Signature 才是用来防止伪造和篡改的关键

二、HS256 与 RS256 的核心区别

1. HS256:对称加密(HMAC + SHA-256)

原理
signature = HMAC_SHA256(
    header.payload,
    secretKey
)
  • 使用 同一个密钥
  • 既负责 签名,也负责 验签
特点
  • 实现简单
  • 性能高
  • 适合单体应用或内部系统
安全隐患(重点)

任何拿到 secretKey 的服务,都可以伪造 Token

在微服务或第三方校验场景中,这是不可接受的。


2. RS256:非对称加密(RSA + SHA-256)

原理
私钥(Private Key) → 签名
公钥(Public Key) → 验签
signature = RSA_SHA256(
    header.payload,
    privateKey
)
特点
  • 私钥只存在于认证中心
  • 公钥可下发给所有资源服务
  • 验签方无法伪造 Token
为什么更安全?

即使公钥泄露,也无法反推出私钥

因此:

  • OAuth2
  • 单点登录
  • 微服务架构
    几乎全部使用 RS256。

3. HS256 vs RS256 对比总结

对比项 HS256 RS256
密钥类型 对称密钥 非对称密钥
密钥数量 1 个 2 个(公钥 / 私钥)
是否适合微服务
是否支持安全密钥轮换 困难 容易
安全边界 较弱
性能 更快 稍慢

三、JWT 验签流程到底在做什么?

很多人会把「验签」和「是否有效」混为一谈,其实这是两个完全不同的阶段。

验签做的事情只有一件:

1. 取出 header.payload
2. 使用约定的算法 + 服务端密钥
3. 重新计算 signature'
4. 与 token 中的 signature 对比

结果只有两种:

  • ❌ 不一致 → Token 被篡改(直接无效)
  • ✅ 一致 → 只能说明 Token 是“真的”

⚠️ 注意:

验签通过 ≠ Token 还能用


四、Token 的「失效」是怎么判断的?

关键结论

JWT 的失效不是“算出来的”,而是“读出来的”

失效信息在 Payload 里。


五、最核心的失效字段:exp

1. exp 是什么?

{
  "sub": "10086",
  "iat": 1700000000,
  "exp": 1700003600
}
  • exp:expiration time(过期时间,秒级时间戳)

2. 判断逻辑

if (now > exp) {
    token 已过期
}

重要认知

  • exp 不影响签名是否正确
  • 它只是 payload 中的一个字段
  • 所以会出现:
情况 结果
签名正确 + exp 未过期 Token 有效
签名正确 + exp 已过期 Token 失效
签名错误 Token 无效

六、完整的 Token 有效性判断流程(生产级)

真实系统中,一个请求的 JWT 校验流程是:

1️⃣ 校验签名(防伪)
2️⃣ 解析 payload
3️⃣ 校验 exp(是否过期)
4️⃣ 校验 nbf / iat(可选)
5️⃣ 业务层校验(是否被吊销、版本是否匹配)

只要 任意一步失败

→ SecurityContext 不会建立
→ 返回 401 / 403

七、除了 exp,还有哪些失效手段?

1. nbf(Not Before)

"nbf": 1700001000

含义:

在该时间之前,Token 不允许被使用


2. 服务端主动让 Token 失效(非常常见)

JWT 是无状态的,但业务不是。

常见方案:

方案一:Token 黑名单(Redis)

  • 登出 / 封禁
  • 把 token / jti 存入 Redis
  • 每次请求校验

方案二:用户版本号

{
  "uid": 1,
  "ver": 3
}
  • 数据库中版本是 4
  • Token 中是 3
  • 判定失效

八、Access Token + Refresh Token 的设计

推荐实践:

Access Token:15 分钟
Refresh Token:7 天
  • Access Token 过期 → 走刷新流程
  • Refresh Token 过期 → 重新登录

这也是 JWT 能做到“无状态 + 可控失效”的关键。


九、和 Spring Security 的整体执行链路

在 Spring Security 中,真实流程是:

请求进入
→ JWT Filter
→ 校验签名
→ 校验 exp
→ 校验业务状态
→ 构造 Authentication
→ 放入 SecurityContext
→ @AuthenticationPrincipal 生效

十、总结一句话记住

🔐 签名解决的是「有没有被伪造」
exp 解决的是「现在还能不能用」
🧠 业务校验解决的是「我还认不认你」


结语

  • HS256:适合简单、封闭系统
  • RS256:生产环境首选,安全边界清晰
  • JWT 有效 ≠ 验签通过
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐