Vue3+Axios企業(yè)級完整實現雙Token無感刷新
前言
在前后端分離架構中,基于 Token 的 JWT 鑒權是目前最主流的身份認證方案。但傳統(tǒng)單 Token 模式存在明顯短板:令牌時效過短會導致用戶頻繁掉線,時效過長又會極大增加信息泄露風險,嚴重影響產品體驗與系統(tǒng)安全性。雙 Token 無感刷新機制是業(yè)界標準的最優(yōu)解決方案,能夠在用戶無感知的前提下靜默續(xù)期身份憑證,無需彈窗、無需跳轉、不中斷業(yè)務操作。本文將從原理剖析、前端工程化落地、后端 JWT 簽發(fā)、并發(fā)問題優(yōu)化、企業(yè)級安全規(guī)范五大維度,提供一套可直接上線的生產級完整方案。
一、為什么需要無感刷新
單 Token 模式無法同時兼顧「安全性」與「用戶體驗」:若令牌有效期較短,用戶正常操作會被強制下線;若有效期過長,一旦令牌被盜,攻擊者可長期冒用身份,存在極高安全漏洞。
無感刷新的核心價值:通過長短雙令牌分離職責,在保證接口安全的前提下,自動靜默續(xù)期登錄狀態(tài),實現用戶永久在線、全程無感知,徹底解決主動掉線問題。
二、雙 Token 機制原理
雙 Token 機制的核心設計思想是職責拆分、長短搭配,用短期令牌保障接口安全,用長期令牌負責身份續(xù)期,從架構層面解決安全與體驗的沖突。兩枚令牌各司其職、互不干擾:
- Access Token(業(yè)務短期令牌) :有效期建議 15–60 分鐘,專門用于業(yè)務接口鑒權。短時效設計可以大幅縮小令牌泄露的風險窗口,保障接口訪問安全,是用戶訪問資源的核心憑證。
- Refresh Token(刷新長期令牌) :有效期建議 7–30 天,僅用于刷新 Access Token,不參與任何業(yè)務請求。作為身份續(xù)期的唯一憑證,用于靜默續(xù)期登錄狀態(tài)。
整套無感刷新?lián)碛型暾]環(huán)邏輯,運行機制清晰、穩(wěn)定性強,具體流程如下:
- 用戶登錄校驗成功后,后端同步返回全新的 Access Token 與 Refresh Token
- 前端本地持久化雙令牌,所有業(yè)務請求自動攜帶 Access Token 完成鑒權
- Access Token 過期失效,接口請求返回 401 未授權狀態(tài)碼
- 前端攔截 401 錯誤,自動調用刷新接口,攜帶 Refresh Token 申請新憑證
- 刷新成功:更新本地雙令牌,自動重試失敗的業(yè)務請求,用戶操作全程無感知
- 刷新失?。号卸ㄩL效憑證過期、登錄態(tài)徹底失效,清空本地緩存,跳轉登錄頁重新授權
三、前端完整實現(Vue3 + Axios)
1、登錄邏輯:雙令牌獲取與本地持久化
const login = async () => {
const userInfo = { username: 'zs', password: '123' }
const { data } = await userLogin(userInfo)
// 存儲雙Token
localStorage.setItem('access_token', data.access_token)
localStorage.setItem('refresh_token', data.refresh_token)
isLogin.value = true
}
2、請求攔截器:統(tǒng)一掛載鑒權頭部
api.interceptors.request.use(config => {
const token = localStorage.getItem('access_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
3、響應攔截器:生產級并發(fā)防重刷 + 自動續(xù)期 + 請求重試
// 核心全局變量:解決多接口并發(fā)401重復刷新BUG
// 刷新鎖:控制同一時間僅執(zhí)行一次token刷新
let isRefreshing = false
// 請求隊列:存儲刷新期間失敗的所有業(yè)務請求
let requestQueue = []
api.interceptors.response.use(
// 正常響應直接返回
res => res,
// 統(tǒng)一處理異常響應
async error => {
const { response, config } = error || {}
const status = response?.status
const isRefreshApi = config.url === '/refresh'
// 非401錯誤、刷新接口自身報錯,直接拋出異常,不做處理
if (status !== 401 || isRefreshApi) {
return Promise.reject(error)
}
// 場景一:正在刷新中,將當前失敗請求推入隊列,等待刷新完成重試
if (isRefreshing) {
return new Promise(resolve => {
requestQueue.push(() => resolve(api(config)))
})
}
// 場景二:無刷新進行中,開啟鎖,執(zhí)行刷新邏輯
isRefreshing = true
try {
// 調用刷新接口,更新雙令牌
await refreshToken()
// 刷新成功:批量執(zhí)行隊列中所有等待請求
requestQueue.forEach(cb => cb())
// 清空隊列,避免臟數據殘留
requestQueue = []
// 重試當前失敗的接口
return api(config)
} catch (e) {
// 刷新失?。簉efresh_token 徹底失效,重置登錄態(tài)
localStorage.clear()
requestQueue = []
window.location.href = '/login'
return Promise.reject(e)
} finally {
// 無論成功失敗,最終釋放刷新鎖,允許下次刷新
isRefreshing = false
}
}
)
4、刷新函數封裝:統(tǒng)一更新本地令牌
async function refreshToken() {
const rt = localStorage.getItem('refresh_token')
const { data } = await api.get('/refresh', { params: { token: rt } })
localStorage.setItem('access_token', data.access_token)
localStorage.setItem('refresh_token', data.refresh_token)
return data
}
四、后端完整實現(Node.js + Express + JWT)
1、登錄接口:簽發(fā)長短雙令牌
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: '賬號或密碼錯誤' })
// 生成短時效訪問Token + 長時效刷新Token
const access_token = generateToken(user, '1h')
const refresh_token = generateToken(user, '7d')
res.json({ access_token, refresh_token, userInfo: user })
})
2、令牌刷新接口:續(xù)期新憑證
app.get('/refresh', (req, res) => {
const { token } = req.query
try {
const userData = verifyToken(token)
const access_token = generateToken(userData, '1h')
const refresh_token = generateToken(userData, '7d')
res.json({ access_token, refresh_token })
} catch (err) {
res.status(401).json({ message: '刷新令牌已失效' })
}
})
3、JWT工具類:統(tǒng)一簽發(fā)與校驗
const jwt = require('jsonwebtoken')
const secret = 'MY_SECRET_KEY'
function generateToken(user, expiresIn) {
return jwt.sign({ username: user.username }, secret, { expiresIn })
}
function verifyToken(token) {
return jwt.verify(token, secret)
}
module.exports = { generateToken, verifyToken }
五、整體業(yè)務閉環(huán)梳理
- 業(yè)務請求發(fā)起,請求攔截器自動攜帶有效 Access Token
- AccessToken 過期或無效,后端返回 401 未授權狀態(tài)碼
- 前端攔截 401 鑒權失敗狀態(tài),靜默阻斷報錯,自動調用令牌刷新接口
- 刷新接口請求成功,更新本地雙令牌,自動重試失敗的原始請求
- 刷新接口請求失敗,判定登錄態(tài)失效,清空本地憑證,跳轉登錄頁重新授權
六、企業(yè)級安全規(guī)范與生產避坑指南
- 合理配置 AccessToken 時效:推薦 15–60 分鐘短期有效期,縮小令牌泄露風險窗口,保障接口鑒權安全
- 嚴格管控 RefreshToken 時效:有效期控制在 7–30 天,禁止永久有效,防止長效令牌被盜用造成長期風險
- 生產環(huán)境強制開啟 HTTPS:全程加密傳輸,防止中間人抓包劫持令牌,保障傳輸鏈路安全
- 優(yōu)化 RefreshToken 存儲方案:生產環(huán)境優(yōu)先使用 HttpOnly + Secure Cookie 存儲,規(guī)避 LocalStorage 帶來的 XSS 竊取漏洞
- 開啟令牌輪換機制:每次刷新同步更新 RefreshToken,主動作廢舊令牌,避免舊令牌被復用攻擊
- 刷新接口增加安全校驗:后端需對刷新接口做限流、IP 綁定、設備標識校驗,抵御惡意刷令牌攻擊
- 敏感業(yè)務二次鑒權:支付、權限配置、賬號核心操作等接口,不可僅依賴 Token,需增加二次身份校驗機制
- 規(guī)范 JWT 載荷數據:Payload 僅存儲用戶ID、賬號等非敏感標識,嚴禁存入密碼、密鑰、權限核心數據
- 規(guī)范前端令牌存儲:避免明文令牌長期暴露在可被JS讀取的存儲中,降低XSS竊取風險
- 解決并發(fā)重復刷新致命BUG(生產核心優(yōu)化) :多接口同時401會觸發(fā)多次刷新,造成令牌覆蓋、請求報錯。本文采用「刷新鎖 + 請求隊列」機制,全局僅執(zhí)行一次刷新,其余請求排隊重試,徹底解決并發(fā)刷新問題,代碼已完全落地可直接使用
- 刷新失敗強制清空登錄態(tài):刷新異常時徹底清除本地令牌緩存,杜絕臟數據導致的循環(huán)報錯、無限重試問題
到此這篇關于Vue3+Axios企業(yè)級完整實現雙Token無感刷新的文章就介紹到這了,更多相關Vue3+Axios雙Token無感刷新內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

