JWT(JSON Web Token)详解
什么是 JWT
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。JWT 是一个紧凑的、URL 安全的令牌,通常用于身份验证和信息交换。
核心特点
- 自包含:JWT 包含所有必要的信息,无需在服务器端存储会话信息
- 无状态:服务器不需要存储用户状态,适合分布式系统
JWT(JSON Web Token)是一种用于在各方之间安全传输信息的开放标准。它由 Header、Payload 和 Signature 三部分组成,具有无状态、自包含和跨域友好的特点。 JWT 的工作原理、结构组成、优势劣势及适用场景,涵盖了身份验证、单点登录等常见用例。同时提供了 Node.js、Python 和前端 JavaScript 的代码示例,阐述了密钥管理、存储安全、令牌过期处理等安全考量与最佳实践,帮助开发者在微服务和分布式架构中有效实施 JWT 认证方案。
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。JWT 是一个紧凑的、URL 安全的令牌,通常用于身份验证和信息交换。
JWT 由三部分组成,用点(.)分隔:
Header.Payload.Signature
包含令牌类型和签名算法信息:
{"alg":"HS256","typ":"JWT"}
alg:签名算法(如 HS256、RS256 等)typ:令牌类型,通常为 "JWT"包含声明(claims),有三种类型:
iss(issuer):签发者sub(subject):主题aud(audience):受众exp(expiration time):过期时间nbf(not before):生效时间iat(issued at):签发时间jti(JWT ID):JWT 唯一标识可以自定义,但需要避免冲突
自定义的声明,用于在同意使用它们的各方之间共享信息
示例 Payload:
{"sub":"1234567890","name":"John Doe","iat":1516239022,"exp":1516242622,"role":"admin"}
用于验证令牌的完整性和真实性:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
客户端 服务器 | | |-- 1. 登录请求 --------->| | |-- 2. 验证凭据 | |-- 3. 生成 JWT |<-- 4. 返回 JWT ---------| | | |-- 5. 携带 JWT 请求 ------>| | |-- 6. 验证 JWT |<-- 7. 返回资源 ---------|
最常见的用途,用于替代传统的 session-based 认证
在各方之间安全地传输信息
在多个应用间共享用户身份
为 RESTful API 提供无状态认证
适合移动应用的认证需求
npm install jsonwebtoken
const jwt = require('jsonwebtoken');
// 密钥(生产环境中应使用环境变量)
const secretKey = 'your-secret-key';
// 用户信息
const user = { id: 1, username: 'john_doe', role: 'admin' };
// 生成 JWT
const token = jwt.sign({ sub: user.id, username: user.username, role: user.role }, secretKey, {
expiresIn: '1h', // 1 小时过期
issuer: 'your-app',
audience: 'your-users'
});
console.log('Generated JWT:', token);
const jwt = require('jsonwebtoken');
// 验证 JWT 中间件
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return res.status(403).json({ error: 'Invalid token' });
}
req.user = decoded;
next();
});
};
// 使用示例
app.get('/protected', authenticateToken, (req, res) => {
res.json({ message: 'This is a protected route', user: req.user });
});
const refreshTokens = new Set(); // 生产环境中应使用数据库
// 生成访问令牌和刷新令牌
const generateTokens = (user) => {
const accessToken = jwt.sign({ sub: user.id, username: user.username }, secretKey, {
expiresIn: '15m'
});
const refreshToken = jwt.sign({ sub: user.id, type: 'refresh' }, secretKey, {
expiresIn: '7d'
});
refreshTokens.add(refreshToken);
return { accessToken, refreshToken };
};
// 刷新令牌端点
app.post('/refresh', (req, res) => {
const { refreshToken } = req.body;
if (!refreshToken || !refreshTokens.has(refreshToken)) {
return res.status(403).json({ error: 'Invalid refresh token' });
}
try {
const decoded = jwt.verify(refreshToken, secretKey);
if (decoded.type !== 'refresh') {
return res.status(403).json({ error: 'Invalid token type' });
}
// 生成新的访问令牌
const newAccessToken = jwt.sign({ sub: decoded.sub }, secretKey, {
expiresIn: '15m'
});
res.json({ accessToken: newAccessToken });
} catch (error) {
res.status(403).json({ error: 'Invalid refresh token' });
}
});
pip install PyJWT
import jwt
import datetime
from functools import wraps
# 密钥
SECRET_KEY = 'your-secret-key'
def generate_token(user_id, username, role):
"""生成 JWT 令牌"""
payload = {
'sub': user_id,
'username': username,
'role': role,
'iat': datetime.datetime.utcnow(),
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return token
def verify_token(token):
"""验证 JWT 令牌"""
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
return payload
except jwt.ExpiredSignatureError:
raise Exception('Token has expired')
except jwt.InvalidTokenError:
raise Exception('Invalid token')
def token_required(f):
"""装饰器:需要 JWT 令牌"""
@wraps(f)
def decorated(*args, **kwargs):
token = None
if 'Authorization' in request.headers:
auth_header = request.headers['Authorization']
try:
token = auth_header.split(" ")[1] # Bearer TOKEN
except IndexError:
return {'message': 'Token format invalid'}, 401
if not token:
return {'message': 'Token is missing'}, 401
try:
data = verify_token(token)
current_user = data
except Exception as e:
return {'message': str(e)}, 401
return f(current_user, *args, **kwargs)
return decorated
# 使用示例
@app.route('/protected')
@token_required
def protected(current_user):
return {'message': 'This is a protected route', 'user': current_user}
// 存储 JWT
localStorage.setItem('accessToken', token);
// 发送请求时携带 JWT
const apiCall = async (url, options = {}) => {
const token = localStorage.getItem('accessToken');
const config = {
...options,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
...options.headers
}
};
try {
const response = await fetch(url, config);
if (response.status === 401) {
// 令牌过期,尝试刷新
await refreshToken();
// 重新发送请求
return fetch(url, config);
}
return response;
} catch (error) {
console.error('API call failed:', error);
throw error;
}
};
// 刷新令牌
const refreshToken = async () => {
const refreshToken = localStorage.getItem('refreshToken');
try {
const response = await fetch('/api/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ refreshToken })
});
if (response.ok) {
const { accessToken } = await response.json();
localStorage.setItem('accessToken', accessToken);
} else {
// 刷新失败,重定向到登录页
window.location.href = '/login';
}
} catch (error) {
console.error('Token refresh failed:', error);
window.location.href = '/login';
}
};
问题:用户在使用过程中令牌过期 解决方案:
问题:CORS 策略阻止 JWT 传输 解决方案:
问题:无法主动撤销 JWT 解决方案:
问题:客户端存储 JWT 的安全风险 解决方案:
问题:大量请求导致验证性能问题 解决方案:
JWT 是一种强大的身份验证和信息交换标准,特别适合现代 Web 应用和微服务架构。通过理解 JWT 的结构、工作原理和安全考虑,可以有效地在项目中使用 JWT。
关键要点:
选择合适的认证方案需要根据具体需求和安全要求来决定。JWT 不是万能的,但在合适的场景下,它是一个优秀的选择。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online