一、为什么需要 JWT?(Session vs Token)
在前后端分离、微服务架构大行其道的今天,JWT(JSON Web Token)几乎成为了身份认证的代名词。
很多开发者只知道它是一个'长长的字符串',用来做登录校验,但并不清楚它内部的运作机制,以及它在安全性上的潜在风险。本文将从原理、结构、流程、以及最核心的生产陷阱四个维度进行详细拆解。
JWT 是前后端分离架构中常用的身份认证方案,相比传统 Session 具有无状态、易扩展等优势。 JWT 的 Header、Payload 和 Signature 结构,强调 Payload 未加密的安全风险。针对 JWT 无法主动注销的缺陷,提出了黑名单机制和双 Token(Access Token + Refresh Token)的解决方案。最后总结了生产环境中的安全避坑清单,包括 HTTPS 传输、算法验证、敏感数据保护及密钥管理,确保系统安全性。
在前后端分离、微服务架构大行其道的今天,JWT(JSON Web Token)几乎成为了身份认证的代名词。
很多开发者只知道它是一个'长长的字符串',用来做登录校验,但并不清楚它内部的运作机制,以及它在安全性上的潜在风险。本文将从原理、结构、流程、以及最核心的生产陷阱四个维度进行详细拆解。
一句话总结:
Session 是把'通行证'存在服务器,给你个号码;JWT 是把'通行证'直接印发给你,服务器只负责查验真伪。
一个标准的 JWT 字符串看起来是这样的:
xxxxx.yyyyy.zzzzz
它由 3 部分 组成,中间用 . 分隔:
描述 Token 的元数据,通常包含两部分:
{ "alg": "HS256", // 签名算法,如 HMAC SHA256 或 RSA
"typ": "JWT" // 令牌类型 }
Base64Url 编码后,构成第一部分。
这是最核心的部分,存放有效信息(Claims)。包含标准字段和自定义字段:
{ "sub": "1234567890", // 用户 ID
"name": "John Doe", // 自定义字段
"admin": true, // 自定义字段
"iat": 1516239022, // 签发时间
"exp": 1516242622 // 过期时间 (非常重要) }
Base64Url 编码后,构成第二部分。
生产高危警告: Payload 只是进行了 Base64 编码,并没有加密! 任何人拿到 Token 都能解码看到 Payload 内容。 绝对不要在 Payload 中放入密码、手机号等敏感信息!
Signature 的本质是一个 MAC(Message Authentication Code):
用密钥对一段消息做不可逆摘要
它同时解决两个问题:
以最常见的 HS256(HMAC + SHA256) 为例:
signature = HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
假设我们有:
{ "alg": "HS256", "typ": "JWT" }
Base64Url 编码后:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
{ "sub": "1001", "admin": false, "exp": 1700000000 }
Base64Url 编码后:
eyJzdWIiOiIxMDAxIiwiYWRtaW4iOmZhbHNlLCJleHAiOjE3MDAwMDAwMDB9
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMDAxIiwiYWRtaW4iOmZhbHNlLCJleHAiOjE3MDAwMDAwMDB9
HMACSHA256(data, secret)
得到 Signature:
Xk8Zk0gQZKZP6u9M1KxZPzXqZk8rQ2kR2WZc9F7d2Gs
Header.Payload.Signature
假设黑客做了这件事:
{ "admin": false } ↓ { "admin": true }
因为Secret 不在黑客手里:
HMACSHA256(新 Header + 新 Payload, ???)
服务器收到 Token 后会:
重点结论: JWT 的安全性完全依赖 Secret 是否泄露
JWT 虽好,但它有一个核心缺陷:一旦签发,无法撤回(Stateless)。
因为服务端不存状态,用户点击'注销'后,只要 Token 还没过期,如果被黑客截获,依然可以使用。
解决方案:
JWT 过期时间设太长不安全,设太短用户体验差(老是需要重新登录)。
最佳实践:双 Token 机制
流程:
| 维度 | Session | JWT |
|---|---|---|
| 状态存储 | 服务端(内存/Redis) | 客户端(自带数据) |
| 扩展性 | 差(需 Session 共享) | 极好(无状态) |
| 安全性 | 防 CSRF 较麻烦,需防 Session 劫持 | 需防 XSS,签名防篡改 |
| RESTful | 不符合(有状态) | 符合(无状态) |
| 性能 | 需查库/查缓存 | CPU 计算签名(略耗 CPU) |
| 注销 | 容易(服务端删 Session) | 难(需黑名单机制) |
在生产环境使用 JWT,请务必检查以下几点:
JWT 规范:RFC 7519

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online