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

