本文目录导读:

JWT(JSON Web Token)是实现无状态认证的主流方案,所谓“无状态”,是指服务端不需要存储会话信息(如 Session),所有用户身份信息都编码在 Token 中,服务端只需验证 Token 的签名即可。
以下是使用 JWT 实现无状态认证的完整流程、代码示例和最佳实践。
JWT 的结构
一个 JWT 由三部分组成,用 分隔:
header.payload.signature
- Header:声明类型和签名算法(如 HS256、RS256)。
- Payload:存放用户信息(如 userId、role)和声明(如过期时间
exp)。 - Signature:对前两部分进行签名,防止篡改。
无状态认证流程
sequenceDiagram
participant Client as 客户端
participant Server as 服务端
Client->>Server: 1. POST /login (用户名+密码)
Server->>Server: 2. 验证密码,生成JWT
Server-->>Client: 3. 返回JWT
Client->>Server: 4. 请求API + Authorization: Bearer <JWT>
Server->>Server: 5. 验证JWT签名和过期时间
Server-->>Client: 6. 返回资源
关键点:
- 服务端不存 Session,只依赖 JWT 中的信息。
- JWT 由服务端签发,客户端保存在 localStorage 或 Cookie 中。
- 每次请求携带 JWT,服务端验证签名后即可识别用户。
具体实现(Node.js + Express 示例)
安装依赖
npm install jsonwebtoken express
登录接口(签发 JWT)
const jwt = require('jsonwebtoken');
const express = require('express');
const app = express();
app.use(express.json());
// 模拟用户数据库(实际应查 DB)
const users = [{ id: 1, username: 'alice', password: '123456' }];
// 密钥(生产环境用环境变量)
const SECRET_KEY = 'your-256-bit-secret';
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
if (!user) return res.status(401).json({ message: '认证失败' });
// 生成 JWT,payload 只存必要信息
const token = jwt.sign(
{
userId: user.id,
role: 'user' // 可以放角色等
},
SECRET_KEY,
{ expiresIn: '1h' } // 设置过期时间
);
res.json({ token });
});
认证中间件(验证 JWT)
const authMiddleware = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer <token>
if (!token) return res.status(401).json({ message: '未提供认证令牌' });
try {
const decoded = jwt.verify(token, SECRET_KEY);
req.user = decoded; // 将用户信息注入请求对象
next();
} catch (err) {
// token 过期或无效
return res.status(401).json({ message: '令牌无效或已过期' });
}
};
// 受保护路由
app.get('/profile', authMiddleware, (req, res) => {
res.json({
userId: req.user.userId,
message: '这是受保护的资源'
});
});
客户端使用(前端示例)
// 登录成功后存储 token
fetch('/login', { method: 'POST', body: JSON.stringify({ username, password }) })
.then(res => res.json())
.then(data => {
localStorage.setItem('token', data.token);
});
// 请求携带 token
fetch('/profile', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
});
关键注意事项
安全存储 Token
- 前端:优先放在
httpOnlyCookie 中(可防 XSS 攻击),localStorage。 - 后端:不要在 JWT 中存放敏感信息(如密码),payload 是 Base64 编码,可被解码。
签名算法选择
- HS256(对称加密):简单,但密钥需保密,适合单体应用。
- RS256(非对称加密):使用公钥/私钥对,私钥由认证服务持有,其他服务可用公钥验证,适合微服务架构。
过期与刷新
- 短期 Token:如 15 分钟,减少泄露风险。
- Refresh Token:长期有效的令牌(如 7 天),用于获取新的 Access Token。
// 刷新接口示例 app.post('/refresh', (req, res) => { const refreshToken = req.body.refreshToken; // 验证 refreshToken(可以存数据库或使用另一个密钥签名) // 返回新的 accessToken });
注销问题
- 无状态 Token 一旦签发,在过期前无法主动失效。
- 解决方案:
- 黑名单机制:维护一个撤销列表(有状态,但仅存储已撤销的 Token)。
- 短期 Token + Refresh Token:Refresh Token 被撤销,强制用户重新登录。
性能与优化
- 每次验证需解密并校验签名,比 Session 的简单查内存慢。
- 可使用缓存(如 Redis)缓存公钥或验证结果。
完整代码仓库示例(FastAPI + Python 版本)
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
app = FastAPI()
security = HTTPBearer()
SECRET_KEY = "your-secret-key"
# 创建 JWT
@app.post("/login")
def login(username: str, password: str):
user = {"id": 1, "username": "alice"} # 实际需验证密码
token = jwt.encode({"userId": user["id"], "exp": 3600}, SECRET_KEY, algorithm="HS256")
return {"access_token": token}
# 验证中间件
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
try:
payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=["HS256"])
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(401, "Token expired")
except jwt.InvalidTokenError:
raise HTTPException(401, "Invalid token")
@app.get("/protected")
def protected_route(user=Depends(verify_token)):
return {"user_id": user["userId"]}
| 特性 | 传统 Session | JWT 无状态 |
|---|---|---|
| 存储 | 服务端内存/Redis | 客户端存储 Token |
| 扩展性 | 需共享 Session 存储 | 天然支持跨服务 |
| 注销 | 立即删除 Session | 需额外机制 |
| 性能 | 查存储 O(1) | 解密验证 O(n) |
最佳实践:
- 使用
RS256签名(微服务场景)。 - Token 不要超过 8KB(避免 HTTP 头过大)。
- 敏感操作(支付、改密)需额外验证(如 OTP)。
- 始终使用 HTTPS 传输。
JWT 的无状态特性使其特别适合分布式系统、移动端和前后端分离场景,但需要配合刷新令牌和黑名单机制解决注销和续期问题。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播