Vue前后端實(shí)現(xiàn)token自動續(xù)期的方法詳解
在前后端分離架構(gòu)中,Token 是實(shí)現(xiàn)身份認(rèn)證的核心機(jī)制,但 Token 過期會導(dǎo)致用戶操作中斷,影響體驗(yàn)。因此,自動續(xù)期方案是保障用戶持續(xù)訪問的關(guān)鍵。以下是幾種主流的 Token 自動續(xù)期方案,包含原理、實(shí)現(xiàn)細(xì)節(jié)及安全性考量。
一、刷新 Token(Refresh Token)機(jī)制
這是目前最成熟、應(yīng)用最廣泛的方案,核心是通過“雙 Token 體系”實(shí)現(xiàn)續(xù)期,兼顧安全性和用戶體驗(yàn)。
1. 核心原理
- Access Token(訪問令牌):短期有效(如 15 分鐘),用于接口訪問,權(quán)限范圍小,泄露風(fēng)險(xiǎn)低。
- Refresh Token(刷新令牌):長期有效(如 7 天),僅用于獲取新的 Access Token,權(quán)限范圍僅為“續(xù)期”,泄露影響可控。
當(dāng) Access Token 過期時(shí),前端用未過期的 Refresh Token 向后端換取新的 Access Token,避免用戶重新登錄。
2. 前后端實(shí)現(xiàn)流程
前端實(shí)現(xiàn)(以 Axios 為例)
1.存儲 Token:Access Token 存在內(nèi)存或 httpOnly Cookie(推薦,防 XSS);Refresh Token 存在 httpOnly Cookie(避免前端 JS 讀取,增強(qiáng)安全性)。
2.請求攔截器:每次請求在 Header 中攜帶 Access Token(如 Authorization: Bearer {accessToken})。
3.響應(yīng)攔截器:處理 401 錯誤(Access Token 過期):
- 若存在 Refresh Token,調(diào)用后端“刷新接口”獲取新 Access Token。
- 刷新成功后,更新本地 Access Token,并重試原請求。
- 若 Refresh Token 也過期(刷新接口返回 401),則清除本地 Token,跳轉(zhuǎn)至登錄頁。
// 響應(yīng)攔截器示例
axios.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
// 若為401且未嘗試過刷新
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true; // 標(biāo)記已嘗試刷新,避免重復(fù)請求
try {
// 調(diào)用刷新接口(Refresh Token 通過 Cookie 自動攜帶)
const { data } = await axios.post('/api/refresh-token');
// 更新本地 Access Token
localStorage.setItem('accessToken', data.accessToken);
// 重試原請求(攜帶新 Token)
originalRequest.headers['Authorization'] = `Bearer ${data.accessToken}`;
return axios(originalRequest);
} catch (refreshError) {
// 刷新失敗(Refresh Token 過期),跳轉(zhuǎn)登錄
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);4.并發(fā)請求處理:若多個(gè)請求同時(shí)觸發(fā) 401,需避免重復(fù)刷新 Token??赏ㄟ^“鎖機(jī)制”實(shí)現(xiàn):刷新過程中阻塞其他請求,等待新 Token 生成后統(tǒng)一重試。
后端實(shí)現(xiàn)
1.生成 Token:登錄成功時(shí),同時(shí)生成 Access Token(短期)和 Refresh Token(長期),返回給前端(Access Token 可放響應(yīng)體,Refresh Token 放 httpOnly Cookie)。
2.驗(yàn)證 Access Token:接口請求時(shí),驗(yàn)證 Access Token 的簽名和有效期,無效則返回 401。
3.刷新接口實(shí)現(xiàn):
- 接收 Refresh Token(從 Cookie 或請求體獲取),驗(yàn)證其有效性(是否存在于數(shù)據(jù)庫、未過期、未被吊銷)。
- 驗(yàn)證通過后,生成新的 Access Token(和新的 Refresh Token,可選,增強(qiáng)安全性)。
- 返回新 Token 給前端。
// 后端刷新接口示例(偽代碼)
@PostMapping("/api/refresh-token")
public Result refreshToken(HttpServletRequest request) {
// 從 Cookie 獲取 Refresh Token
String refreshToken = CookieUtils.getCookieValue(request, "refreshToken");
if (refreshToken == null) {
return Result.fail(401, "刷新令牌不存在");
}
// 驗(yàn)證 Refresh Token(查庫+驗(yàn)簽)
RefreshTokenEntity entity = refreshTokenMapper.selectByToken(refreshToken);
if (entity == null || entity.getExpireTime().before(new Date())) {
return Result.fail(401, "刷新令牌已過期");
}
// 生成新 Access Token 和 Refresh Token
String newAccessToken = JwtUtils.generateAccessToken(entity.getUserId());
String newRefreshToken = JwtUtils.generateRefreshToken(entity.getUserId());
// 更新數(shù)據(jù)庫中的 Refresh Token(舊的標(biāo)記失效,存儲新的)
refreshTokenMapper.invalidateOldToken(entity.getId());
refreshTokenMapper.insert(new RefreshTokenEntity(newRefreshToken, entity.getUserId()));
// 返回新 Token(Access Token 放響應(yīng)體,Refresh Token 放 httpOnly Cookie)
return Result.success(Map.of(
"accessToken", newAccessToken,
"refreshToken", newRefreshToken // 可選,通過 Cookie 返回更安全
));
}3. 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):安全性高(Access Token 短期有效,泄露影響小;Refresh Token 可吊銷);用戶體驗(yàn)好(無需頻繁登錄)。
- 缺點(diǎn):實(shí)現(xiàn)較復(fù)雜(需維護(hù)雙 Token 邏輯);需后端存儲 Refresh Token(增加存儲成本)。
二、滑動窗口續(xù)期(無 Refresh Token)
適用于對安全性要求中等、希望簡化實(shí)現(xiàn)的場景,核心是“Token 快過期時(shí)自動延長有效期”。
1. 核心原理
- 僅使用一個(gè) Access Token,有效期設(shè)為中等(如 1 小時(shí))。
- 當(dāng) Token 剩余有效期小于閾值(如 10 分鐘)時(shí),前端請求接口時(shí),后端自動生成新 Token 并返回,前端更新本地 Token。
- 本質(zhì)是“用持續(xù)活躍的請求延長 Token 有效期”,類似“用戶活躍則會話不失效”。
2. 前后端實(shí)現(xiàn)流程
前端實(shí)現(xiàn)
存儲 Token 并在請求頭攜帶。
每次收到響應(yīng)后,檢查是否包含新 Token(如響應(yīng)頭 X-New-Token),若有則更新本地存儲。
// 響應(yīng)攔截器示例
axios.interceptors.response.use(
(response) => {
// 若響應(yīng)頭有新 Token,更新本地存儲
const newToken = response.headers['x-new-token'];
if (newToken) {
localStorage.setItem('accessToken', newToken); // 建議用 Cookie
}
return response;
},
(error) => {
// 若 Token 已過期(401),直接跳轉(zhuǎn)登錄
if (error.response?.status === 401) {
window.location.href = '/login';
}
return Promise.reject(error);
}
);
后端實(shí)現(xiàn)
Token 中包含過期時(shí)間(如 exp 字段)。
每次驗(yàn)證 Token 時(shí),計(jì)算剩余有效期:若剩余時(shí)間 < 閾值(如 10 分鐘),則生成新 Token,放在響應(yīng)頭(如 X-New-Token)返回。
// 驗(yàn)證 Token 并判斷是否續(xù)期(偽代碼)
public String validateAndRenewToken(String token) {
// 驗(yàn)證 Token 簽名和有效性
Claims claims = JwtUtils.parseToken(token);
if (claims == null) {
throw new TokenInvalidException();
}
// 計(jì)算剩余有效期(當(dāng)前時(shí)間到 exp 的差值)
long expireTime = claims.getExpiration().getTime();
long remainingTime = expireTime - System.currentTimeMillis();
// 若剩余時(shí)間 < 10 分鐘,生成新 Token
if (remainingTime < 10 * 60 * 1000) {
String newToken = JwtUtils.generateAccessToken(claims.getSubject()); // 用原用戶 ID 生成新 Token
return newToken;
}
return null; // 無需續(xù)期
}3. 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡單(無需維護(hù) Refresh Token);用戶體驗(yàn)流暢(無感續(xù)期)。
- 缺點(diǎn):安全性較低(Token 有效期較長,泄露后風(fēng)險(xiǎn)更高);無法處理“用戶長時(shí)間不操作”的場景(Token 會直接過期)。
三、主動預(yù)檢續(xù)期
適用于對請求成功率要求高的場景,前端主動檢測 Token 有效期,提前續(xù)期。
1. 核心原理
- 前端每次發(fā)送請求前,檢查 Token 剩余有效期:
- 若剩余時(shí)間 > 閾值(如 5 分鐘):直接發(fā)送請求。
- 若剩余時(shí)間 ≤ 閾值:先發(fā)送續(xù)期請求獲取新 Token,再發(fā)送原請求。
- 避免了“請求因 Token 過期失敗后重試”的情況,更主動。
2. 前后端實(shí)現(xiàn)流程
前端實(shí)現(xiàn)(請求攔截器中處理)
axios.interceptors.request.use(async (config) => {
const token = localStorage.getItem('accessToken');
if (!token) {
window.location.href = '/login';
return Promise.reject(new Error('未登錄'));
}
// 解析 Token 中的過期時(shí)間(需前端解析 JWT,或后端返回過期時(shí)間)
const payload = JSON.parse(atob(token.split('.')[1]));
const expireTime = payload.exp * 1000; // JWT 的 exp 是秒級時(shí)間戳
const remainingTime = expireTime - Date.now();
// 若剩余時(shí)間 ≤ 5 分鐘,先續(xù)期
if (remainingTime <= 5 * 60 * 1000) {
try {
const { data } = await axios.post('/api/renew-token', { token });
const newToken = data.newToken;
localStorage.setItem('accessToken', newToken);
config.headers['Authorization'] = `Bearer ${newToken}`;
} catch (error) {
// 續(xù)期失敗,跳轉(zhuǎn)登錄
window.location.href = '/login';
return Promise.reject(error);
}
} else {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});
后端實(shí)現(xiàn)
- 提供專門的續(xù)期接口(
/api/renew-token),接收舊 Token,驗(yàn)證有效性后返回新 Token。 - 邏輯與滑動窗口的后端類似,但觸發(fā)時(shí)機(jī)由前端主動控制。
3. 優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):避免請求失敗重試,成功率高;主動處理續(xù)期,流程更可控。
- 缺點(diǎn):增加了一次預(yù)檢請求(性能損耗?。?;需前端解析 Token 過期時(shí)間(JWT 可解析,非 JWT 需后端額外返回)。
四、安全性與最佳實(shí)踐
Token 存儲:
- 優(yōu)先用
httpOnly + Secure + SameSiteCookie 存儲(防 XSS、CSRF 攻擊)。 - 避免用
localStorage/sessionStorage(易被 XSS 竊?。?。
過期時(shí)間設(shè)置:
- Access Token:短期(15 分鐘 ~ 1 小時(shí)),減少泄露影響。
- Refresh Token:中期(7 ~ 30 天),兼顧體驗(yàn)與安全;可設(shè)置“絕對過期時(shí)間”(如 30 天),強(qiáng)制用戶定期登錄。
Refresh Token 輪換:每次用 Refresh Token 換取新 Access Token 時(shí),同步生成新的 Refresh Token(舊的立即失效),防止 Refresh Token 被復(fù)用。
HTTPS 傳輸:所有 Token 必須通過 HTTPS 傳輸,防止中間人攻擊。
并發(fā)請求處理:用“鎖機(jī)制”(如 Promise 等待)處理多個(gè)請求同時(shí)觸發(fā)續(xù)期的場景,避免重復(fù)調(diào)用刷新接口。
Token 吊銷:后端需支持主動吊銷 Token(如用戶登出、修改密碼時(shí)),可通過“黑名單”(Redis 存儲已吊銷 Token)實(shí)現(xiàn)快速驗(yàn)證。
總結(jié)
- 追求安全性:優(yōu)先選 Refresh Token 機(jī)制(雙 Token 體系)。
- 追求簡單實(shí)現(xiàn):選 滑動窗口續(xù)期(無 Refresh Token)。
- 追求請求成功率:選 主動預(yù)檢續(xù)期(前端提前處理)。
實(shí)際場景中,可結(jié)合業(yè)務(wù)需求(如用戶活躍度、安全等級)選擇方案,核心是在“用戶體驗(yàn)”與“安全性”之間找到平衡。
到此這篇關(guān)于Vue前后端實(shí)現(xiàn)token自動續(xù)期的方法詳解的文章就介紹到這了,更多相關(guān)前后端token續(xù)期內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JAVA實(shí)現(xiàn)Token自動續(xù)期機(jī)制的示例代碼
- Vue如何優(yōu)雅處理Token過期并自動續(xù)期
- SpringBoot基于Redis實(shí)現(xiàn)token的在線續(xù)期的實(shí)踐
- springboot+vue實(shí)現(xiàn)Token自動續(xù)期(雙Token方案)
- SpringBoot中Token登錄授權(quán)、續(xù)期和主動終止的方案流程分析
- SpringBoot實(shí)現(xiàn)JWT token自動續(xù)期的示例代碼
- Spring?Boot實(shí)現(xiàn)JWT?token自動續(xù)期的實(shí)現(xiàn)
相關(guān)文章
Vue實(shí)現(xiàn)雙向綁定的原理以及響應(yīng)式數(shù)據(jù)的方法
這篇文章主要介紹了Vue實(shí)現(xiàn)雙向綁定的原理以及響應(yīng)式數(shù)據(jù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07
Vue前端空值處理的實(shí)戰(zhàn)指南與避坑記錄
本文旨在幫助同學(xué)們學(xué)會在前端真實(shí)業(yè)務(wù)項(xiàng)目里,到底該怎么寫空值處理(?.、??、||、if判斷、兜底邏輯),以及為什么這么選、會踩哪些高頻坑,順便幫大家拉直JS/TS空值、真值假值的基礎(chǔ)概念,助力你們寫出規(guī)范可維護(hù)的團(tuán)隊(duì)級代碼2026-03-03
vue3+ts重復(fù)參數(shù)提取成方法多處調(diào)用以及字段無值時(shí)不傳字段給后端問題
在進(jìn)行API開發(fā)時(shí),優(yōu)化參數(shù)傳遞是一個(gè)重要的考量,傳統(tǒng)方法中,即使參數(shù)值為空,也會被包含在請求中發(fā)送給后端,這可能會導(dǎo)致不必要的數(shù)據(jù)處理,而優(yōu)化后的方法則只會傳遞那些實(shí)際有值的字段,從而提高數(shù)據(jù)傳輸?shù)挠行院秃蠖颂幚淼男?/div> 2024-10-10
vue-cli 3.0 自定義vue.config.js文件,多頁構(gòu)建的方法
今天小編就為大家分享一篇vue-cli 3.0 自定義vue.config.js文件,多頁構(gòu)建的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09
Vue使用JSEncrypt實(shí)現(xiàn)rsa加密及掛載方法
這篇文章主要介紹了Vue使用JSEncrypt實(shí)現(xiàn)rsa加密及掛載方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
vite2.x實(shí)現(xiàn)按需加載ant-design-vue@next組件的方法
這篇文章主要介紹了vite2.x實(shí)現(xiàn)按需加載ant-design-vue@next組件的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03最新評論

