JWT基本工作流程
-
用户登录时颁发Token :
- 用户提供用户名和密码
- 服务器验证凭据
- 验证成功后,服务器生成JWT并返回给客户端
- 客户端存储这个Token(通常在localStorage、sessionStorage或cookie中)
-
后续请求携带Token :
- 每次API请求都在HTTP头中携带Token
- 格式: Authorization: Bearer [token]
- 服务器验证Token的有效性和权限
Token刷新策略
关于Token过期处理,有两种主要策略:
策略1:主动刷新(推荐)
在Token快过期时主动刷新 ,而不是等到完全过期:
// 检查Token是否即将过期(比如还有5分钟过期)
function isTokenExpiringSoon(token) {
try {
const payload = JSON.parse(atob(token.split('.')[1]));
const currentTime = Date.now() / 1000;
const timeUntilExpiry = payload.exp - currentTime;
// 如果还有5分钟(300秒)就过期,则需要刷新
return timeUntilExpiry < 300;
} catch {
return true;
}
}
// 在请求拦截器中检查并刷新
api.interceptors.request.use(async (config) => {
const token = localStorage.getItem('accessToken');
if (token && isTokenExpiringSoon(token)) {
try {
const newToken = await refreshToken();
localStorage.setItem('accessToken', newToken);
config.headers.Authorization = `Bearer ${newToken}`;
} catch (error) {
// 刷新失败,跳转到登录页
window.location.href = '/login';
}
} else if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
策略2:被动刷新
等Token过期后再处理 :
// 响应拦截器处理401错误
api.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
try {
const newToken = await refreshToken();
localStorage.setItem('accessToken', newToken);
// 重试原始请求
error.config.headers.Authorization = `Bearer ${newToken}`;
return api.request(error.config);
} catch (refreshError) {
// 刷新失败,跳转登录
localStorage.clear();
window.location.href = '/login';
}
}
return Promise.reject(error);
}
);
双Token机制(最佳实践)
实际项目中通常使用 Access Token + Refresh Token 的组合:
- Access Token :短期有效(15-30分钟),用于API请求
- Refresh Token :长期有效(7-30天),用于获取新的Access Token
// 登录成功后获得两个Token
{
"accessToken": "eyJhbGciOiJIUzI1NiIs...", // 30分钟过期
"refreshToken": "eyJhbGciOiJIUzI1NiIs...", // 7天过期
"user": { ... }
}
// 刷新Token的函数
async function refreshToken() {
const refreshToken = localStorage.getItem('refreshToken');
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ refreshToken })
});
if (response.ok) {
const data = await response.json();
return data.accessToken;
} else {
throw new Error('Refresh failed');
}
}
推荐的刷新时机
-
主动刷新 (推荐):
- 在Token还有5-10分钟过期时主动刷新
- 用户体验更好,不会中断操作
- 可以在后台静默进行
-
被动刷新 :
- 收到401错误时再刷新
- 实现简单,但可能影响用户体验
- 适合对实时性要求不高的应用
安全考虑
-
Refresh Token存储 :
- 使用httpOnly cookie存储(更安全)
- 或者存储在安全的客户端存储中
-
Token轮换 :
- 每次刷新时同时更新Refresh Token
- 防止Refresh Token被盗用
-
失效处理 :
- Refresh Token过期时,强制用户重新登录
- 可以记住用户名,简化重新登录流程 总的来说, 主动刷新策略配合双Token机制 是目前最佳的实践方案,既保证了安全性,又提供了良好的用户体验。
文章标签
冬眠
博主专注于技术、阅读与思考。在这里记录学习、思考与生活。
系列:JWT 实战
第 2 篇,共 5 篇
