本文目录
什么是 JWT?
JSON Web Token(JWT)是一种紧凑且 URL 安全的令牌格式,用于以 JSON 对象的形式在各方之间安全地传输信息。一个 JWT 由三个以点号分隔、经 Base64URL 编码的部分组成:header.payload.signature(头部.载荷.签名)。头部指定签名算法,载荷包含声明(数据),签名则用于校验令牌未被篡改。
JWT 实现了无状态身份认证——服务器无需存储会话数据,因为所有必要信息都嵌入在令牌本身之中。这使得 JWT 非常适合分布式系统、微服务和 API,在这些场景中,会话存储会带来额外的复杂性和延迟。
JWT 结构详解
每个 JWT 都由三个不同的部分组成,各自在令牌的生命周期中承担特定的用途:
- 头部(Header)——一个 JSON 对象,指定令牌类型(typ: JWT)和签名算法(alg: HS256、RS256 等),随后进行 Base64URL 编码
- 载荷(Payload)——一个 JSON 对象,包含 iss(签发者)、sub(主题)、exp(过期时间)、iat(签发时间)等声明,以及你需要传输的任何自定义数据
- 签名(Signature)——通过用密钥(HMAC)或私钥(RSA/ECDSA)对已编码的头部和载荷进行签名而生成,用于确保令牌的完整性
载荷未经加密——任何人都可以解码并读取它。切勿在 JWT 载荷中存放密码或信用卡号等敏感信息。签名只保证数据未被修改,而非保证数据被隐藏。
签名算法
签名算法的选择决定了 JWT 签名如何生成和校验。主要有三大类算法:
- HMAC(HS256、HS384、HS512)——对称算法,签名和校验使用同一个密钥。实现简单,最适合签发方和校验方共享同一密钥的单服务器场景
- RSA(RS256、RS384、RS512)——非对称算法,使用私钥签名、公钥校验。非常适合分布式系统,因为多个服务无需访问签名密钥即可校验令牌
- ECDSA(ES256、ES384、ES512)——使用椭圆曲线密码学的非对称算法。以显著更小的密钥尺寸和更快的运算速度提供与 RSA 相当的安全性,非常适合移动和物联网应用
对于大多数 Web 应用,当令牌的签发方和使用方是同一台服务器时,HS256 便已足够。当令牌需要由第三方或跨不同服务进行校验时,请选择 RS256 或 ES256。
免费试用 —— 无需注册
创建并签名 JWT →编码与解码
编码一个 JWT 意味着通过组装头部、载荷,并用你的密钥或私钥生成签名来创建一个新令牌。这通常在服务器端于登录或令牌刷新时完成。生成的令牌字符串会被发送给客户端,用于后续经过身份认证的请求。
解码一个 JWT 可能意味着两件事:在不校验签名的情况下提取载荷声明(便于在客户端读取令牌元数据),或者完整校验签名以确认令牌真实且未被篡改。生产系统在信任载荷中的任何声明之前,都应始终校验签名。
常见使用场景
在 Web 和移动应用中,JWT 已成为现代身份认证与授权模式的标准:
- API 身份认证——客户端在每次请求时将 JWT 放入 Authorization 头部(Bearer 令牌),使服务器无需查询数据库即可校验身份
- OAuth 2.0 访问令牌——OAuth 提供方将 JWT 作为访问令牌签发,其中携带用于授权 API 访问的作用域和权限信息
- 微服务通信——各服务之间传递 JWT,从而在无需集中式会话存储的情况下,跨服务边界传播用户身份和权限
- 单点登录(SSO)——由中央身份提供方签发一个 JWT,供多个应用接受,使用户只需认证一次即可访问所有互联的服务
安全最佳实践
JWT 功能强大,但需要谨慎实现,以避免常见的安全隐患:
- 设置较短的过期时间——访问令牌的 exp 声明设为 15 分钟到 1 小时,并为更长的会话实现刷新令牌轮换
- 切勿在载荷中存放敏感数据——JWT 载荷仅经过 Base64URL 编码,并未加密。任何持有令牌的人都能读取其中的声明
- 始终校验所有声明——在每次请求时校验 exp、iss、aud 以及任何自定义声明。在未完整校验签名之前,不要信任载荷
- 只使用 HTTPS——仅通过加密连接传输 JWT,以防令牌被中间人攻击截获
- 拒绝 “none” 算法——始终校验 alg 头部与你预期的算法一致。“none” 算法会完全绕过签名校验
常见问题
JWT 和会话 Cookie 有什么区别?
会话 Cookie 在客户端存储一个会话 ID,而实际的会话数据存放在服务器上。JWT 是自包含的——所有数据都在令牌本身之中。这使 JWT 无状态且更易于横向扩展,但也更难撤销,因为你无法像删除服务端会话那样简单地将其删除。对于传统 Web 应用,会话 Cookie 更简单;而对于 API 和分布式系统,JWT 更优。
如何在 JWT 过期之前撤销它?
由于 JWT 是无状态的,它没有内置的撤销机制。常见策略包括:维护一个令牌黑名单(在每次请求时进行比对)、使用配合刷新令牌轮换的短期访问令牌(撤销刷新令牌即可使未来的访问失效),或者在用户记录中存储一个令牌版本号并在登出时递增它。
JWT 有大小限制吗?
JWT 规范中没有正式的大小限制,但实际存在限制。大多数 HTTP 服务器将头部大小限制为 8 KB。由于 JWT 通常放在 Authorization 头部中发送,建议将令牌控制在 4 KB 以下。含有大量声明的庞大载荷可能超出此限——可考虑在 JWT 中只存储必要的声明,其余数据则通过 API 获取。