JSON Web Token (JWT) 是一个开放标准 (RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间安全地传输 JSON 对象形式的信息。由于此信息是经过数字签名的,因此可以被验证和信任。JWT 是现代 Web 应用中 API 安全和身份验证的热门选择。

📋 目录

关键要点

  • 结构:JWT由三部分组成:头部、载荷和签名,各部分之间用点分隔。
  • 自包含:载荷包含有关用户的声明(例如,用户ID、角色),从而减少了数据库查找的需求。
  • 安全性:签名用于验证令牌的完整性,确保其未被篡改。
  • 无状态性:由于令牌是自包含的,JWT允许无状态身份验证,服务器无需存储会话状态。
  • 常见用例:是API身份验证、微服务和各方之间安全信息交换的理想选择。
  • 实现:在JavaScript、Python和Java等语言中广泛提供了用于创建和验证JWT的库,简化了集成。

准备好使用JWT了吗?我们的在线JWT解码器工具提供了一种简单的方法来解码、编码和检查您的令牌。您也可以使用我们的Base64编码工具处理Base64编码,或使用JSON格式化工具美化JWT载荷。

JWT的结构剖析

一个 JWT 由三个由点 (.) 分隔的部分组成:

部分 描述
头部 (Header) 关于令牌的元数据。
载荷 (Payload) 声明或数据。
签名 (Signature) 用于验证令牌的完整性。

一个典型的 JWT 如下所示:xxxxx.yyyyy.zzzzz

💡 快速提示: 使用我们的JWT解码工具可以立即查看JWT的三个部分及其内容。

头部(Header)

头部指定了令牌类型 (JWT) 和所使用的签名算法,例如 HMAC SHA256 或 RSA。

{
  "alg": "HS256",
  "typ": "JWT"
}

此 JSON 经过 Base64Url 编码 后形成 JWT 的第一部分。了解更多关于Base64编码原理

载荷(Payload)

载荷包含声明 (claims),这些是关于一个实体(通常是用户)的陈述和附加数据。声明有三种类型:

  • 注册声明 (Registered Claims):预定义的声明,如 iss (签发者)、exp (过期时间)、sub (主题) 和 aud (受众)。建议使用这些声明以实现互操作性。
  • 公共声明 (Public Claims):由开发者自定义的声明,应在 IANA JSON Web Token 注册表中注册以避免冲突。
  • 私有声明 (Private Claims):为特定用例在各方之间创建的自定义声明,它们已同意其含义。

载荷示例:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

载荷也经过 Base64Url 编码 后形成 JWT 的第二部分。

⚠️ 安全警告: 载荷只是Base64编码,并非加密!任何人都可以解码查看内容。不要在载荷中存储敏感信息如密码或信用卡号。

签名(Signature)

签名是通过将编码后的头部、编码后的载荷、一个密钥和头部中指定的算法组合而成的。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your_secret_key
)

签名确保令牌未被篡改,并且在私钥签名的情况下,验证发件人的身份。了解更多关于哈希算法MD5哈希

多语言代码实现

JavaScript实现 (Node.js)

const jwt = require('jsonwebtoken');

// 编码 (签名)
const payload = { sub: '1234567890', name: 'John Doe' };
const secret = 'your-secret-key';
const token = jwt.sign(payload, secret, { expiresIn: '1h' });

// 解码 (验证)
const decoded = jwt.verify(token, secret);

📦 安装依赖: npm install jsonwebtoken

Python实现

import jwt

# 编码
payload = {'sub': '1234567890', 'name': 'John Doe'}
secret = 'your-secret-key'
token = jwt.encode(payload, secret, algorithm='HS256')

# 解码
decoded = jwt.decode(token, secret, algorithms=['HS256'])

📦 安装依赖: pip install pyjwt

Java实现

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;

// 编码
String token = Jwts.builder()
    .setSubject("1234567890")
    .claim("name", "John Doe")
    .signWith(SignatureAlgorithm.HS256, "your-secret-key".getBytes())
    .compact();

// 解码
Claims claims = Jwts.parser()
    .setSigningKey("your-secret-key".getBytes())
    .parseClaimsJws(token)
    .getBody();

📦 Maven依赖:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

JWT安全最佳实践

1. 密钥管理

  • 使用强随机密钥(至少256位)
  • 定期轮换密钥
  • 使用环境变量存储密钥,不要硬编码

2. 令牌存储

  • 优先使用HttpOnly cookie存储
  • 避免使用localStorage(易受XSS攻击)
  • 在HTTPS上传输令牌

3. 过期时间设置

  • 访问令牌:15分钟-1小时
  • 刷新令牌:7-30天
  • 实现刷新令牌机制

4. 载荷安全

  • 不要存储敏感信息
  • 最小化载荷大小
  • 使用JWE加密敏感载荷

🔐 延伸阅读: 了解更多关于Bearer Token认证API安全最佳实践

常见问题解答

1. 我应该在客户端哪里存储JWT?

将JWT存储在HttpOnly cookie中以防止XSS攻击。避免使用localStoragesessionStorage,因为它们容易受到脚本访问的攻击。使用我们的JWT解码工具可以快速检查JWT内容。

2. 如何处理JWT过期和令牌续订?

实现刷新令牌机制。当访问令牌过期时,使用一个长寿命的刷新令牌来请求新的访问令牌,而无需用户重新登录。推荐访问令牌有效期15-60分钟,刷新令牌7-30天。

3. JWT、JWS和JWE有什么区别?

  • JWT是标准(RFC 7519)
  • **JWS (JSON Web Signature)**是签名的JWT,确保完整性
  • **JWE (JSON Web Encryption)**是加密的JWT,确保机密性

大多数情况下使用的是JWS。

4. JWT是加密方法吗?

不,标准的JWS是签名的,而不是加密的。任何截获令牌的人都可以看到有效载荷。如果需要加密有效载荷,请使用JWE。了解更多关于Base64编码和加密的区别。

5. JWT令牌多大合适?

建议控制在1KB以内。过大的JWT会增加网络传输开销和cookie大小限制问题。只在载荷中包含必要的声明。

6. 如何撤销JWT?

JWT本身是无状态的,无法直接撤销。常见方案:

  • 维护令牌黑名单
  • 缩短过期时间
  • 使用刷新令牌机制
  • 版本化令牌(在载荷中添加版本号)

总结

JWT 为现代应用中的身份验证和信息交换提供了强大而灵活的解决方案。通过了解其结构、流程和安全考量,您可以构建安全、可扩展和无状态的系统。

关键要点回顾

✅ JWT由头部、载荷、签名三部分组成
✅ 使用Base64Url编码,非加密
✅ 适合无状态API认证
✅ 必须使用HTTPS传输
✅ 合理设置过期时间和刷新机制

相关工具推荐

延伸阅读


💡 开始使用: 访问我们的编解码工具分类页探索更多安全工具!