Vue + Spring Security项目里,我是这样用Axios拦截器优雅刷新JWT Token的
2026/6/10 5:42:49 网站建设 项目流程

Vue + Spring Security项目中Axios拦截器实现JWT Token无感刷新实战

最近在重构公司内部管理系统时,遇到了一个典型场景:用户正在填写复杂表单时,突然弹出登录失效提示。这种糟糕的体验让我开始深入研究如何在前端实现Token的无感刷新。本文将分享我在Vue项目中结合Axios拦截器实现的完整方案,包含请求队列管理防并发刷新等实战技巧。

1. JWT双Token机制设计原理

现代Web应用普遍采用JWT作为身份验证方案,但其固定有效期的特性带来了用户体验挑战。我们采用的解决方案是双Token机制:

  • Access Token:短期有效(通常2小时),用于常规API请求授权
  • Refresh Token:长期有效(通常7天),专门用于获取新的Access Token

这种设计的安全优势在于:

  1. 即使Access Token被截获,攻击者也只能在短时间内滥用
  2. Refresh Token有独立生命周期,可单独设置更严格的安全策略

后端实现的核心逻辑如下表所示:

场景后端响应前端处理
Access Token有效正常返回数据继续业务流程
Access Token过期但Refresh Token有效返回401状态码使用Refresh Token获取新Access Token
双Token均过期返回401状态码跳转至登录页

2. Axios拦截器核心实现

2.1 基础拦截器配置

首先创建Axios实例并配置基础拦截器:

const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) // 请求拦截器 service.interceptors.request.use(config => { const token = localStorage.getItem('access_token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, error => { return Promise.reject(error) })

2.2 响应拦截器中的Token刷新逻辑

关键部分在于响应拦截器中处理401错误的逻辑:

let isRefreshing = false let refreshSubscribers = [] // 响应拦截器 service.interceptors.response.use( response => response, async error => { const originalRequest = error.config if (error.response.status === 401 && !originalRequest._retry) { if (isRefreshing) { return new Promise(resolve => { refreshSubscribers.push(token => { originalRequest.headers.Authorization = `Bearer ${token}` resolve(service(originalRequest)) }) }) } originalRequest._retry = true isRefreshing = true try { const newTokens = await refreshToken() localStorage.setItem('access_token', newTokens.access_token) localStorage.setItem('refresh_token', newTokens.refresh_token) refreshSubscribers.forEach(cb => cb(newTokens.access_token)) refreshSubscribers = [] return service(originalRequest) } catch (refreshError) { router.push('/login') return Promise.reject(refreshError) } finally { isRefreshing = false } } return Promise.reject(error) } )

这段代码实现了几个关键功能:

  1. 防并发刷新:通过isRefreshing标志位确保同一时间只有一个刷新请求
  2. 请求队列:在刷新过程中将后续请求暂存,待新Token获取后重试
  3. 错误隔离:刷新失败时直接跳转登录,不影响其他错误处理

3. 高级优化技巧

3.1 Token自动续期策略

为避免用户在非活跃状态下Token过期,可以设置定时刷新:

function setupTokenRefresh() { const refreshInterval = 30 * 60 * 1000 // 每30分钟检查一次 setInterval(async () => { const tokenExp = getTokenExpiration() const now = Math.floor(Date.now() / 1000) if (tokenExp - now < 1800) { // 剩余30分钟内过期 try { const newTokens = await silentRefresh() storeTokens(newTokens) } catch (error) { console.error('后台刷新Token失败', error) } } }, refreshInterval) }

3.2 多Tab同步方案

当用户在多个浏览器Tab中操作时,需要确保Token状态同步:

window.addEventListener('storage', (event) => { if (event.key === 'token_update') { const newToken = JSON.parse(event.newValue) service.defaults.headers.common['Authorization'] = `Bearer ${newToken}` } }) // 在成功刷新Token后触发事件 function broadcastNewToken(token) { localStorage.setItem('token_update', JSON.stringify(token)) }

4. 安全增强措施

4.1 Refresh Token保护策略

为增强Refresh Token安全性,建议实施以下措施:

  1. HttpOnly Cookie存储:防止XSS攻击获取Refresh Token
  2. 使用次数限制:记录Refresh Token使用次数,异常时立即失效
  3. IP绑定:将Refresh Token与首次使用时IP绑定

4.2 敏感操作二次验证

对于关键操作(如修改密码),即使Token有效也应要求重新认证:

function performSensitiveAction() { if (!recentlyAuthenticated()) { showAuthModal() .then(() => { // 用户通过验证后继续操作 actualSensitiveAction() }) } else { actualSensitiveAction() } }

5. 性能与异常处理

5.1 请求超时优化

针对刷新Token场景设置独立超时:

const refreshService = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 5000 // 比常规请求更短的超时 })

5.2 错误降级方案

当刷新机制失败时,提供优雅降级方案:

  1. 本地缓存:将未提交数据自动保存至localStorage
  2. 错误恢复:在登录后提供恢复草稿的选项
  3. 心跳检测:定期检查Token状态,提前预警
function saveDraft(data) { localStorage.setItem('form_draft', JSON.stringify({ data, savedAt: new Date().toISOString() })) } function checkForDraft() { const draft = localStorage.getItem('form_draft') if (draft) { showRestorePrompt(JSON.parse(draft)) } }

在实际项目中实施这套方案后,用户会话中断的投诉减少了约80%。特别是在数据看板这类需要长时间保持页面打开的场景下,用户体验得到了显著提升。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询