✅ 一、JWT 是什么?
JWT(JSON Web Token) 是一种用于 用户身份验证 和 信息安全传输 的令牌机制。它以 JSON 格式的数据 在客户端和服务端之间传递,通常用于用户登录后的授权。
简单说:你登录成功后,服务器发你一个“身份证”——JWT,你之后访问资源就带着它,不用每次都重新登录。
📦 二、JWT 的结构(由三部分组成)
JWT 是一个由 .分隔的三段字符串,格式如下:
header.payload.signature
1️⃣ Header(头部)
说明Token的类型和签名算法:
{
"alg": "HS256",
"typ": "JWT"
}
2️⃣ Payload(负载)
-
存放用户的非敏感信息,比如用户ID、用户名、角色等;
-
也可放一些标准字段如
exp(过期时间):
{
"sub": "123456",
"name": "小杰",
"role": "admin",
"exp": 1710000000
}
3️⃣ Signature(签名)
是用于防篡改的签名,防止中间人修改 Payload:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
🔐 三、JWT 的核心机制
- 用户登录成功,服务器根据用户信息生成一个 JWT(签名加密);
- 客户端保存该 JWT(通常放在浏览器本地存储或前端缓存);
- 每次请求 API 时,把 JWT 放在请求头:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6...
- 服务器解析 JWT,校验签名、检查是否过期,并基于其中的信息完成鉴权。
🎯 四、JWT 的典型使用场景
| 场景 | 说明 |
|---|---|
| 登录认证 | 用户登录后获得令牌 |
| 单点登录(SSO) | 多系统共享登录状态 |
| 接口调用授权 | API 接口访问权限控制 |
| 移动端/前后端分离 | Token 代替传统 Session |
🛡️ 五、JWT 的安全建议
| 安全点 | 建议 |
|---|---|
| 签名密钥保密 | secret 必须保存在服务端,不可泄露 |
| 不存敏感信息 | Payload 是明文可解码,不要放密码、身份证等 |
| 设置过期时间 | 用 exp 字段控制有效期,定期刷新 |
| 使用 HTTPS | 防止 Token 被中间人截获 |
| 加签算法选择 | 推荐 HS256 或 RSA(非对称更安全) |
🧪 六、JWT 示例(真实令牌样式)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOjEyMywidXNlcm5hbWUiOiJ4aWFvamllIn0.
4VzV5Oxf9bAWlLS8MbhMELEzqJKAKFYsKL8TXp6nEbs
你可以把前两段(Header 和 Payload)复制到 jwt.io 查看解码效果。
📁 七、后端中如何生成 JWT?(以 Java 为例)
用 jjwt(Java JWT)库示例:
String jwt = Jwts.builder()
.setSubject("小杰")
.claim("role", "admin")
.setExpiration(new Date(System.currentTimeMillis() + 3600_000)) // 1小时过期
.signWith(SignatureAlgorithm.HS256, "mySecretKey")
.compact();
✅ 总结一句话
JWT 是一种无状态、跨平台的认证机制,安全、高效、前后端分离首选,但也需合理控制过期、签名、防泄露。
补充说明
## ✅ 八、JWT 的优缺点
✅ 优点:
- 无状态(Stateless),不需要服务器维护 Session。
- 支持跨语言、跨平台。
- 支持前端存储在 Cookie、localStorage 或 sessionStorage。
❌ 缺点:
- Token 内容明文,不能存储敏感信息。
- 无法主动注销(需借助黑名单或 Redis 存储)。
- Token 一旦泄露,除非过期否则一直有效。
✅ 第一个问题:Signature 是怎么生成的?
Signature 的生成过程本质上是:
Signature = HMAC-SHA256(
base64urlEncode(header) + "." + base64urlEncode(payload),
secretKey
)
我们来详细分解一下: 📌 步骤一:Base64 编码 Header 和 Payload
Header 原始内容:
{
"alg": "HS256",
"typ": "JWT"
}
→ base64urlEncode → eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload 原始内容:
{
"sub": "user123",
"role": "admin"
}
→ base64urlEncode → eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6ImFkbWluIn0
📌 步骤二:使用 secretKey 和算法生成签名
以 HS256(HMAC with SHA-256) 为例:
HMACSHA256(
data: "eyJhbGci...In0", // header.payload
key: "adminSecretKey" // 密钥
)
→ 输出一个 256-bit 的哈希值 → Signature
生成的签名(Signature)是一串不可逆的哈希,形如:
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
🔑 所谓的“secretKey 签名”是指:
用 secretKey 作为密钥,对前面两部分(header + payload)进行哈希加密运算,得到一段签名数据,用于防止内容被篡改。
- 如果客户端试图修改 payload 中的内容(如把 "role" 从 "user" 改成 "admin"),
- 再次计算签名时将无法匹配,因为它没有服务器的 secretKey。
✅ 二、key 是什么?
key是你的 密钥 secretKey,是你自己系统在服务端定义的一段字符串,比如:
String secretKey = "adminSecretKey";
你可以理解为它是用来保护 Token 的“钥匙”——没有它,就无法伪造或验证 JWT 的合法性。
- 管理员端可以有一个 secretKey(比如:
adminSecretKey) - 用户端也可以有不同的 secretKey(比如:
userSecretKey)
你可以在配置文件里设置:
jwt:
admin-secret-key: adminSecretKey
user-secret-key: userSecretKey
## ✅ 三、HMACSHA256 是怎么处理 data 和 key 的?
HMACSHA256(data, key) 的意思是:
用 key(密钥)对 data(即 header.payload)做一次 哈希加密签名,生成一个固定长度的哈希摘要(就是 Signature)。
具体步骤如下:
- 把
key当作加密的“盐”(盐是密码学里的概念,增强安全性) - 将
data和key一起输入到HMAC-SHA256加密算法中 - 输出一个 256 位(32 字节) 的加密结果(通常再进行 base64 编码)
## ✅ 四、Signature 是干嘛用的?
生成后的 Signature 会和 header + payload 一起组成完整的 JWT:
header.payload.signature
比如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6ImFkbWluIn0
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
当客户端拿着这个 Token 去请求时,服务端就可以用 相同的 secretKey 和算法 对前两段重新计算签名,看结果是否与第三段的 Signature 一致,从而判断 Token 是否被篡改。