跳转至

JWT(JSON Web Token)与 JWKS(JSON Web Key Set)

本文集中记录令牌格式、签名、验签、密钥管理和使用边界,核对时间:2026-09-05。 授权流程与令牌用途见 OAuth 2.0、OIDC 与 PKCE 学习笔记

术语速查

术语 英文全称 中文解释
JWT JSON Web Token JSON Web 令牌,用于承载声明的令牌格式
Claim Claim 声明,对主体或上下文信息的一项断言
JWS JSON Web Signature JSON Web 签名,使用数字签名或消息认证码保护内容完整性
JWE JSON Web Encryption JSON Web 加密,用于加密并保护内容
JWK JSON Web Key JSON Web 密钥,使用 JSON 表示密码学密钥
JWKS JSON Web Key Set JSON Web 密钥集
OAuth 2.0 The OAuth 2.0 Authorization Framework OAuth 2.0 授权框架,用于委托访问资源
OIDC OpenID Connect OpenID Connect 身份认证协议,是建立在 OAuth 2.0 之上的身份层
PKCE Proof Key for Code Exchange 授权码交换证明密钥,用于降低授权码被截获后遭滥用的风险
Access Token Access Token 访问令牌,用于访问受保护资源
Refresh Token Refresh Token 刷新令牌,用于按授权服务器策略获取新的访问令牌
ID Token ID Token(ID 表示 Identity) 身份令牌,OIDC 用它向客户端传递用户认证结果和相关声明
MAC Message Authentication Code 消息认证码,使用共享秘密验证数据完整性和来源
HMAC Hash-based Message Authentication Code 基于哈希函数的消息认证码
SHA-256 Secure Hash Algorithm 256-bit 256 位安全散列算法
HS256 HMAC using SHA-256 使用 SHA-256 的 HMAC 算法
RSA Rivest-Shamir-Adleman 以三位发明者姓氏命名的非对称密码算法
RSASSA RSA Signature Scheme with Appendix RSA 附录式签名方案
PKCS Public-Key Cryptography Standards 公钥密码学标准系列
CRT Chinese Remainder Theorem 中国剩余定理,可用于优化 RSA 私钥运算
RS256 RSASSA-PKCS1-v1_5 using SHA-256 使用 SHA-256 的 RSA PKCS #1 v1.5 签名算法
Base64URL Base 64 Encoding with URL and Filename Safe Alphabet 使用 URL 与文件名安全字符表的 Base64 编码
Base64URLUInt Base64urlUInt-Encoded Integer 使用 Base64URL 编码的无符号整数
UTF-8 Unicode Transformation Format - 8-bit Unicode 的 8 位可变长度字符编码
ASCII American Standard Code for Information Interchange 美国信息交换标准代码
UTC Coordinated Universal Time 协调世界时
API Application Programming Interface 应用程序编程接口
SDK Software Development Kit 软件开发工具包
URL Uniform Resource Locator 统一资源定位符
URI Uniform Resource Identifier 统一资源标识符,URL 是其常见形式
HTTP Hypertext Transfer Protocol 超文本传输协议
HTTPS Hypertext Transfer Protocol Secure 受加密连接保护的 HTTP
X.509 X.509(标准编号,不是缩写) 定义公钥证书及相关验证机制的标准
CSRF Cross-Site Request Forgery 跨站请求伪造
RFC Request for Comments 请求评议文档,互联网标准和技术规范的文档系列

1. JWT 的定位

JWT 是一种承载 Claims(声明)的格式。它可以用 JWS 提供数字签名或 MAC 保护,也可以用 JWE 加密;本文重点介绍常见的 JWS 形式。

OAuth 2.0 的 Access Token 可以采用 JWT,也可以是不透明随机值;Refresh Token 也不要求采用 JWT。OIDC 的 ID Token 使用 JWT,但不能作为普通业务 API 的 Access Token。

方式 常见验证方式 主要取舍
自包含 JWT 使用可信密钥在本地验证,再检查声明 减少逐次远程验证的依赖,但要处理密钥轮换、权限更新和撤销
不透明 Token 内省或查询服务端状态,也可按策略缓存 便于集中管理状态,但依赖服务端查询及缓存策略

本地验签不等于整个登录系统无状态。登录会话、刷新令牌和撤销记录仍可能保存在服务端;共享会话存储也可以用于分布式系统。

2. 结构与 Claims(声明)

2.1 签名 JWT(JWS)的三段结构

常见的签名 JWT 采用以下形式,三段之间用 . 分隔:

BASE64URL(Header) . BASE64URL(Payload) . BASE64URL(Signature)
  • Header(头部):描述算法、令牌类型和密钥编号。
  • Payload(载荷):保存身份、有效期、接收方等声明。
  • Signature(签名):数字签名或 MAC,用于检测篡改并验证密钥持有关系。

Header 和 Payload 的 Base64URL 编码可直接还原,不提供保密性。JWE 是加密表示,不能把所有 JWT 都理解为三段式签名令牌。

2.2 字段示例

以下是虚构的业务令牌字段,不是可直接使用的令牌。实际时间应由签发端生成,示例只演示 Unix 时间戳(从 1970-01-01 00:00:00 UTC 起计算的秒数)及 900 秒有效期。

Header:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "signing-key-1"
}

Header 常见字段:

字段 英文全称 中文解释
alg Algorithm 保护令牌所使用的算法
typ Type 对象类型,JWT 中通常写作 JWT
kid Key ID(Key Identifier) 密钥编号,用于从可信密钥集合中选择密钥

Payload:

{
  "iss": "https://auth.example.com",
  "sub": "user-123",
  "aud": "orders-api",
  "iat": 1800000000,
  "exp": 1800000900,
  "scope": "orders:read"
}

常用 Claims:

字段 英文全称 中文解释 校验重点
iss Issuer 签发者 与预期可信签发者匹配
sub Subject 主体标识,不一定是用户 按签发者和业务约定识别主体
aud Audience 预期接收者,可为字符串或数组 必须包含当前客户端或资源服务器的预期标识
exp Expiration Time 过期时间 当前时间必须早于该时间
nbf Not Before 最早生效时间 当前时间早于该时间时不能接受
iat Issued At 签发时间 用于按策略检查令牌年龄,不代替 exp
jti JWT ID 令牌唯一标识 可关联撤销或重放记录,本身不会自动防重放
scope Scope 授权范围 必须包含接口所需权限,并遵循签发方约定

JWT 基础规范不要求所有场景都携带上述全部字段;必需字段由具体协议和应用确定。scope、角色等声明也要遵循各自约定,不能仅凭字段存在就授权。

2.3 签名输入

下面的 headerpayload 表示 JSON 文本,Base64URL 编码省略末尾填充符:

signing_input = BASE64URL(UTF-8(header)) + "." + BASE64URL(UTF-8(payload))
signature = SIGN_OR_MAC(ASCII(signing_input), key)
jwt = signing_input + "." + BASE64URL(signature)

SIGN_OR_MAC 由约定算法决定。验证时使用收到的前两段原文,而不是把 JSON 解码、重新排版后再计算。实际签发和校验使用成熟库,不手写密码学实现。

3. HS256 与 RS256

对比项 HS256(HMAC using SHA-256) RS256(RSASSA-PKCS1-v1_5 using SHA-256)
算法 HMAC-SHA-256,生成 MAC RSA PKCS #1 v1.5 与 SHA-256,生成数字签名
密钥 签发方与验证方共享秘密 私钥签名,公钥验签
权限边界 持有共享秘密的一方也能生成有效 MAC 仅持有公钥的一方不能生成有效签名
密钥要求 至少 256 位,并使用高熵随机密钥 RSA 密钥至少 2048 位

两者都不是内容加密。多服务场景采用 RS256,可以让资源服务器只持有公钥,避免向所有验证方分发签名秘密;算法选择仍要匹配协议、库和部署要求。

验证端必须预先限制允许的算法,并检查算法与密钥类型、用途一致,不能由收到的 alg 自行决定接受范围。业务认证场景应拒绝未签名令牌和不符合策略的算法。

4. JWK、JWKS 与密钥轮换

JWK 是密钥的 JSON 表示;JWKS 是包含 keys 数组的 JWK 集合。它们可以表示公钥、私钥或对称秘密,公开验签端点只能发布所需的公钥材料

在非对称签名场景中,认证服务器使用私钥签发 JWT,并在 Header 中写入 kid;验证端从预先信任的地址获取 JWKS,根据 kid 选择公钥并验证签名。OIDC Discovery(OpenID Connect Discovery,OpenID Connect 发现机制)使用 jwks_uri(JWK Set URI,JWK 集合地址)声明该地址,/.well-known/jwks.json 是常见路径,但不是必须采用的固定路径。这样可以集中分发公钥,并支持多个密钥并存和密钥轮换。

典型的 RSA 公钥 JWKS:

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "signing-key-1",
      "use": "sig",
      "alg": "RS256",
      "n": "<base64url-encoded-modulus>",
      "e": "AQAB"
    }
  ]
}

RSA 验签公钥常见字段:

字段 英文全称 中文解释
kty Key Type 密钥类型,例如 RSA
kid Key ID(Key Identifier) 密钥编号,用于匹配令牌 Header
use Public Key Use 公钥用途,sig(Signature)表示签名验证
alg Algorithm 预期算法,例如 RS256
n Modulus RSA 公钥模数,以 Base64URLUInt 编码
e Exponent RSA 公钥指数,以 Base64URLUInt 编码

Base64URLUInt 是使用 Base64URL 表示无符号整数的编码方式。示例中的 AQAB 对应常用公钥指数 65537。

kidusealg 是否必需取决于应用约定。公开 JWKS 不应包含以下 RSA 私钥参数,也不能发布对称密钥的 k(Key Value,密钥值):

字段 英文全称 中文解释
d Private Exponent 私钥指数
p First Prime Factor 第一个素因子
q Second Prime Factor 第二个素因子
dp First Factor CRT Exponent 第一个素因子的中国剩余定理指数
dq Second Factor CRT Exponent 第二个素因子的中国剩余定理指数
qi First CRT Coefficient 第一个中国剩余定理系数
oth Other Primes Info 多素数 RSA 的其他素数信息

JWKS 只提供验签所需的密钥材料,不存放 JWT,也不会自动完成令牌校验。签名通过后,验证端仍须检查 issaudexpnbf 等声明以及业务权限。

密钥轮换通常按以下顺序进行:

  1. 发布新公钥,为新旧密钥分配不同 kid
  2. 使用新私钥签发令牌,并在 Header 中携带新 kid
  3. 在正常轮换的过渡期保留旧公钥,让尚未过期的旧令牌继续验证。
  4. 结合旧令牌的最长寿命、时钟偏差和缓存策略退役旧公钥。

验证端可缓存可信 JWKS。遇到未知 kid 时,只从预先信任的来源按受控策略刷新;仍无法找到合适密钥时拒绝令牌,不能跳过验证。私钥泄漏属于紧急事件,不能等待正常过渡期结束才处理。

5. 验证流程

5.1 JWT Access Token(访问令牌)

收到 Access Token
  -> 使用预配置的令牌类型、可信签发者和算法策略
  -> 从可信密钥集合中选择匹配的验签密钥
  -> 验证签名或 MAC
  -> 检查必需声明、iss、aud、exp,以及存在时的 nbf
  -> 检查接口权限与业务数据权限
  -> 允许请求;任一必需检查失败则拒绝

关键约束:

  • 解析出的 Header 和 Payload 在验证前都是不可信输入,kid 匹配也不代表令牌可信。
  • 密钥来源必须由可信配置或经过验证的 Discovery 确定,不能直接请求令牌中任意指定的 jku(JWK Set URL,JWK 集合地址)、x5u(X.509 URL,证书链地址)或 iss 地址。
  • 按所采用的令牌规范验证类型及必需声明,时间字段使用秒级时间,并设置有限的时钟偏差。
  • 签名通过后仍需检查当前 API 的权限及业务对象所有权;令牌中的角色也可能需要结合实时授权状态判断。

5.2 OIDC ID Token(身份令牌)

ID Token 应交给成熟 OIDC SDK 按协议验证,不能与 Access Token 共用不加区分的接受规则:

  • 检查 isssubaudexpiat 等必需声明;aud 必须包含当前客户端的 client_id(Client Identifier,客户端标识),其他受众也须符合信任策略。
  • 使用签发者提供的可信密钥,按协议和客户端协商配置验证密码学保护;接入时优先采用 SDK 的完整验签流程。
  • 请求使用了 nonce(一次性随机值)时,必须检查返回值存在且与本次请求一致,并防止重放。
  • 使用定义了 azp(Authorized Party,被授权方)的扩展时,按该扩展规则验证授权方;请求了 auth_time(Authentication Time,认证时间)或 max_age(Maximum Authentication Age,最长认证时效)时检查认证时间和重新认证要求。

JWT 也能承载 private_key_jwt(使用私钥签名 JWT 的客户端认证方式)等客户端断言。其用途是客户端认证,不是用户登录或访问业务 API,必须使用对应协议的独立验证规则。

6. 使用、过期与撤销

采用 Bearer Token(持有者令牌)认证时,通过 HTTPS 在请求头发送 Access Token:

GET /orders HTTP/1.1
Host: api.example.com
Authorization: Bearer <ACCESS_TOKEN>
  • 不把密码、私钥等秘密放进可读取的 Payload;声明只保留接收方需要的数据。
  • 不把真实令牌写入 URL、日志或示例,也不上传到不受信任的在线解码网站。
  • 本地验签不会自动获知退出登录、账号禁用或权限变更。需要立即失效时,必须配合撤销状态、内省或其他实时检查。
  • 删除客户端保存的 Token,不会让已泄漏的副本失效;停止刷新也不会自动撤销已签发的 Access Token。
  • 仅从 JWKS 删除公钥不能保证立即撤销,因为验证端可能持有缓存;密钥泄漏处置需要协调缓存和拒绝策略。
  • JWT 可以与 Session(会话)、Cookie(浏览器状态数据)同时使用。CSRF 风险取决于浏览器是否自动携带认证凭据,不能由令牌格式单独决定。

7. 自测

问题 核心答案
为什么普通签名 JWT 中不能放密码? Header 和 Payload 可被解码,签名不提供内容保密性
公钥为什么可以公开? 公钥能验签,但不能代替私钥签名;公开端点必须排除秘密材料
为什么验签后还要检查 issaud 和权限? 签名只是一项信任检查,还需确认用途、接收方、有效期和业务授权
JWT 能否在退出登录后立即失效? 取决于服务端是否执行撤销或其他实时状态检查,单纯本地验签无法感知退出

8. 参考资料