Vue+Laravel项目实现自动刷新token与用户无操作自动登出咨询
你现有代码的问题是仅在页面初始化时执行一次计时,没有监听用户操作重置计时,也没有覆盖token刷新的逻辑,可按以下方案实现:
1 实现用户无操作3分钟自动登出
逻辑:监听页面内所有用户活跃事件(鼠标点击、移动、键盘输入、滚动、触摸操作),每次事件触发时重置倒计时,倒计时归0后执行登出逻辑,可直接在main.js中添加如下代码:
// 全局计时器变量 let logoutTimer = null const LOGOUT_DELAY = 3 * 60 * 1000 // 3分钟,单位毫秒 // 重置倒计时函数 const resetLogoutTimer = () => { // 先清除已有计时器 if (logoutTimer) clearTimeout(logoutTimer) // 重新开始计时 logoutTimer = setTimeout(() => { // 执行登出逻辑:清除本地token、跳转到登录页 localStorage.removeItem('token') window.location.href = "domain.com/logout" }, LOGOUT_DELAY) } // 监听用户活跃事件,触发时重置计时器 const userEvents = ['click', 'mousemove', 'keydown', 'scroll', 'touchstart'] userEvents.forEach(event => { window.addEventListener(event, resetLogoutTimer, { passive: true }) }) // 页面初始化时启动第一次计时 resetLogoutTimer()
passive: true 是为了优化滚动事件性能,避免页面卡顿。
2 实现自动刷新Token
推荐用响应拦截器触发刷新的方式,比固定定时刷新更节省资源:
逻辑:配置axios响应拦截器,当接口返回401(Token过期)时,先调用refresh接口获取新token,更新本地存储的token后重发之前失败的请求;如果refresh接口也失败,直接触发登出,代码示例:
import axios from 'axios' // 给axios配置基础域名 axios.defaults.baseURL = 'domain.com' // 标记是否正在刷新token,避免重复调用refresh接口 let isRefreshing = false // 存储刷新期间失败的请求队列 let failedQueue = [] // 请求拦截器:给所有请求头加token axios.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) // 响应拦截器:处理token过期逻辑 axios.interceptors.response.use( response => response, error => { const originalRequest = error.config // 接口返回401且不是refresh请求本身 if (error.response.status === 401 && !originalRequest._retry) { if (isRefreshing) { // 正在刷新的话,把当前请求加入队列,等刷新完成后再执行 return new Promise(resolve => { failedQueue.push(token => { originalRequest.headers.Authorization = `Bearer ${token}` resolve(axios(originalRequest)) }) }) } originalRequest._retry = true isRefreshing = true return axios.post('/api/refresh') .then(res => { const newToken = res.data.token localStorage.setItem('token', newToken) axios.defaults.headers.common.Authorization = `Bearer ${newToken}` // 刷新成功后执行队列里的所有请求 failedQueue.forEach(callback => callback(newToken)) failedQueue = [] return axios(originalRequest) }) .catch(() => { // 刷新token失败,直接登出 localStorage.removeItem('token') window.location.href = "domain.com/logout" return Promise.reject(error) }) .finally(() => { isRefreshing = false }) } return Promise.reject(error) } )
注意事项
- 后端Laravel需要配置好Token刷新逻辑,确保
/api/refresh接口可以正常返回新的Token,Token的有效期建议设置为1-2小时,刷新Token的有效期可以设置为7天左右,和前端逻辑匹配 - 如果需要适配多标签页场景,可以监听
storage事件,当其他标签页清除Token时,当前标签页也同步触发登出 - 若对安全性要求较高,建议将Token存储在HttpOnly Cookie中,避免XSS攻击窃取Token的风险
内容的提问来源于stack exchange,提问作者tarafikttes
相关产品推荐
相关产品推荐

