JWT + HttpOnly Cookie 简介
这是一种目前广泛使用的前后端分离认证方案,结合了 JWT 的无状态特性和 HttpOnly Cookie 的安全优势。
什么是 JWT ?
JWT(JSON Web Token) 是一种紧凑的、自包含的令牌格式,用于在客户端和服务器之间安全传输信息。
JWT 结构
header.payload.signature
| 部分 | 内容 | 示例 |
|---|---|---|
| Header | 算法类型、令牌类型 | {"alg":"HS256","typ":"JWT"} |
| Payload | 用户信息、过期时间等 | {"userId":123,"role":"admin","exp":1700000000} |
| Signature | 签名,防篡改 | 使用密钥对 header+payload 签名 |
传统 JWT 存放方式的问题
方式1:localStorage / sessionStorage
// 登录后存储
localStorage.setItem('token', jwtToken)
// 每次请求手动携带
axios.defaults.headers.common['Authorization'] = `Bearer ${jwtToken}`
风险:XSS 攻击可直接读取 localStorage,窃取 JWT。
方式2:普通 Cookie
document.cookie = `token=${jwtToken}`
风险:同样可被 JavaScript 读取,且易受 CSRF 攻击。
JWT + HttpOnly Cookie 方案
工作原理
用户登录 → 服务器生成 JWT → 通过 Set-Cookie 放入 HttpOnly Cookie →
浏览器自动在后续请求中携带该 Cookie → 服务器验证 JWT流程图
┌──────────┐ POST /login ┌──────────┐
│ │ ──────────────────────────────> │ │
│ 浏览器 │ { username, password } │ 服务器 │
│ │ <────────────────────────────── │ │
└──────────┘ Set-Cookie: token=JWT; HttpOnly; Secure; SameSite=Strict
│ │
│ 后续请求自动携带 Cookie │
│ ────────────────────────────────────────> │
│ Authorization: Bearer JWT (Cookie) │ 验证JWT
│ <──────────────────────────────────────── │
│ 返回数据 │代码实现示例
后端(Node.js + Express)
const jwt = require('jsonwebtoken')
// 登录接口
app.post('/login', (req, res) => {
const { username, password } = req.body
// 验证用户名密码...
const user = { id: 123, role: 'admin' }
// 生成 JWT
const token = jwt.sign(user, 'secret_key', { expiresIn: '7d' })
// 通过 HttpOnly Cookie 返回
res.cookie('token', token, {
httpOnly: true, // 禁止 JavaScript 读取
secure: true, // 仅 HTTPS
sameSite: 'strict', // 防止 CSRF
maxAge: 7 * 24 * 60 * 60 * 1000 // 7天过期
})
res.json({ message: '登录成功' })
})
// 验证中间件
const authMiddleware = (req, res, next) => {
const token = req.cookies.token // 从 Cookie 中读取
if (!token) return res.status(401).json({ error: '未登录' })
try {
const decoded = jwt.verify(token, 'secret_key')
req.user = decoded
next()
} catch (err) {
res.status(401).json({ error: '令牌无效' })
}
}
// 受保护的接口
app.get('/profile', authMiddleware, (req, res) => {
res.json({ user: req.user })
})
前端(Vue 示例)
// 登录 - 无需手动处理 token
async login(username, password) {
await axios.post('/api/login', { username, password })
// Cookie 由浏览器自动管理,无需前端存储
}
// 请求受保护资源 - Cookie 自动携带
async getProfile() {
const res = await axios.get('/api/profile')
return res.data
}
// 登出 - 清除 Cookie
async logout() {
await axios.post('/api/logout')
}
优缺点对比
| 对比项 | 传统 localStorage + JWT | HttpOnly Cookie + JWT |
|---|---|---|
| XSS 防护 | ❌ 易被窃取 | ✅ JavaScript 无法读取 |
| CSRF 防护 | ✅ 需手动携带 | ❌ 需配合 SameSite 或 CSRF Token |
| 前端便捷性 | ❌ 需手动管理 | ✅ 浏览器自动处理 |
| 跨域支持 | ✅ 灵活 | ⚠️ 需配置 CORS withCredentials |
| 移动端/API 调用 | ✅ 方便携带 | ⚠️ 需额外处理 |
最佳实践组合
HttpOnly Cookie + Secure + SameSite=Strict + CSRF Token| 配置 | 作用 |
|---|---|
HttpOnly |
防止 XSS 窃取 JWT |
Secure |
仅 HTTPS 传输 |
SameSite=Strict |
防止 CSRF 攻击 |
CSRF Token |
额外一层 CSRF 防护(可选) |
一句话总结
JWT + HttpOnly Cookie 就是把 JWT 放在浏览器自动管理的 HttpOnly Cookie 中,既保留了 JWT 的无状态优势,又避免了 XSS 攻击窃取令牌的风险,是目前前后端分离项目中最推荐的认证方案之一。
