在现代 Web 应用中,认证(Authentication) 是绕不开的话题。随着前后端分离、微服务、Serverless 的普及,传统的 Session 方案逐渐暴露出扩展性和跨域上的局限,JWT(JSON Web Token) 因此成为主流选择之一。
本文将从 JWT 是什么 → 如何工作 → 前后端如何落地 → 安全注意事项 → 最佳实践 五个层面,带你真正吃透 JWT。
一、JWT 是什么?解决了什么问题
JWT(JSON Web Token)是一种用于在各方之间安全传输信息的自包含令牌标准(RFC 7519)。
一句话概括:
JWT 是一个“服务器签名过的、客户端可以携带的身份凭证”
为什么需要 JWT?
传统 Session 模式的问题:
| 问题 | 说明 |
|---|---|
| 服务端有状态 | Session 存在服务器内存 / Redis |
| 扩展成本高 | 多实例需 Session 共享 |
| 跨域不友好 | Cookie 限制多 |
| 移动端不自然 | App 没有 Cookie |
JWT 的优势:
- ✅ 无状态(服务端不存 Session)
- ✅ 天然支持前后端分离
- ✅ 适合微服务、网关统一鉴权
- ✅ 移动端 / 小程序友好
二、JWT 的结构与工作原理
1️⃣ JWT 的三段式结构
JWT 本质是一个字符串,由三部分组成:
Header.Payload.Signature
Header(头部)
{
"alg": "HS256",
"typ": "JWT"
}
说明签名算法和类型。
Payload(载荷)
{
"sub": "10001",
"username": "admin",
"exp": 1735689600,
"iat": 1735686000
}
常见字段:
| 字段 | 含义 |
|---|---|
| sub | 用户唯一标识 |
| iat | 签发时间 |
| exp | 过期时间 |
| iss | 签发者 |
| aud | 接收方 |
⚠️ Payload 是 Base64 编码,不是加密,任何人都能解码查看
Signature(签名)
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
作用:
- 防篡改
- 验证 JWT 是否由可信服务器签发
2️⃣ JWT 的认证流程(核心)
用户登录
↓
服务端校验账号密码
↓
生成 JWT(签名)
↓
返回给客户端
↓
客户端存储 JWT
↓
后续请求携带 JWT
↓
服务端校验签名 & 有效期
三、前后端如何使用 JWT(实战流程)
1️⃣ 登录阶段(后端)
// 登录成功后生成 JWT
import jwt from 'jsonwebtoken'
function generateToken(user) {
return jwt.sign(
{
sub: user.id,
username: user.username,
},
process.env.JWT_SECRET,
{
expiresIn: '2h',
issuer: 'api.example.com',
}
)
}
✅ 只放必要信息
❌ 不要放密码、手机号、权限全集
2️⃣ 客户端如何存 JWT?
| 存储方式 | 是否推荐 | 原因 |
|---|---|---|
| localStorage | ❌ | 容易被 XSS 读取 |
| sessionStorage | ❌ | 同样有 XSS 风险 |
| Cookie(HttpOnly) | ✅ | 无法被 JS 读取 |
| 内存(变量) | ✅ | 刷新即失效 |
👉 推荐方案:HttpOnly + Secure Cookie
3️⃣ 请求时如何携带 JWT
标准做法:Authorization Header
Authorization: Bearer <token>
前端示例:
fetch('/api/user', {
headers: {
Authorization: `Bearer ${token}`,
},
})
4️⃣ 服务端中间件校验 JWT
import jwt from 'jsonwebtoken'
function authMiddleware(req, res, next) {
const auth = req.headers.authorization
if (!auth) return res.status(401).end()
const token = auth.replace('Bearer ', '')
try {
const payload = jwt.verify(token, process.env.JWT_SECRET)
req.user = payload
next()
} catch {
res.status(401).end()
}
}
四、JWT 常见误区与安全风险
❌ 误区 1:JWT 是加密的
JWT 不是加密的,只是签名
任何人都可以解码 Payload。
❌ 误区 2:JWT 一旦签发就无法失效
JWT 无法主动失效,除非:
- 等过期
- 使用黑名单(Redis)
- 使用短 Token + Refresh Token
❌ 误区 3:JWT 里放权限列表很方便
问题:
- Token 体积变大
- 权限变更无法即时生效
👉 建议只放 userId,权限实时查
🔥 主要安全风险
| 风险 | 防御措施 |
|---|---|
| XSS | HttpOnly Cookie |
| CSRF | SameSite + Token 校验 |
| Token 泄露 | HTTPS + 短有效期 |
| 重放攻击 | jti + 黑名单 |
五、进阶方案:Access Token + Refresh Token
为什么需要 Refresh Token?
- Access Token 过期时间短(如 15 分钟)
- Refresh Token 生命周期长(如 7 天)
- 提升安全性与用户体验
流程示意
登录 → Access Token + Refresh Token
Access Token 过期
↓
使用 Refresh Token 换新 Access Token
Refresh Token 的存储建议
- 只存在服务端(数据库 / Redis)
- 客户端只存一个标识或 HttpOnly Cookie
六、JWT 最佳实践总结(强烈建议)
✅ 设计层面
- Token 尽量短
- 只存必要信息
- 明确过期时间
✅ 安全层面
- 全站 HTTPS
- HttpOnly + Secure Cookie
- 使用 Refresh Token
- 设置
aud / iss
✅ 架构层面
- 网关统一鉴权
- 微服务只信任网关
- Token 黑名单兜底
七、JWT 是否适合你?
| 场景 | 是否推荐 JWT |
|---|---|
| 前后端分离 | ✅ |
| 移动端 / 小程序 | ✅ |
| 微服务架构 | ✅ |
| 纯 SSR + Cookie | ❌ |
结语
JWT 并不是“银弹”,而是一把需要正确使用的利器。
真正安全、优雅的认证方案,永远是 机制 + 规范 + 约束 的组合。
如果你正在设计登录系统、统一鉴权方案,JWT + Refresh Token + HttpOnly Cookie,依然是当下最成熟可靠的选择之一。
文章评论