LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

【JavaScript】無感刷新Token:如何做到讓用戶“永不掉線”

admin
2025年7月9日 12:40 本文熱度 284

沒有什么比在用戶操作得正嗨時,突然提示“登錄已過期,請重新登錄”的提示更讓人沮喪的了。這種突兀的中斷不僅破壞了用戶體驗,甚至可能導致未保存的數據丟失。

然而,我們都知道,出于安全考慮,用于身份驗證的 Token(通常是 Access Token)必須有較短的有效期。那么,我們如何在保證安全的前提下,創造一種“永不掉線”的絲滑體驗呢?

問題的根源:Access Token 的“天生矛盾”

首先,我們要理解為什么需要刷新 Token。

我們通常使用 Access Token 來驗證用戶的每一次 API 請求。為了安全,Access Token 的生命周期被設計得很短(例如 30 分鐘或 1 小時)。如果有效期太長,一旦泄露,攻擊者就能在很長一段時間內冒充用戶進行操作,風險極高。

這就產生了一個矛盾:

  • 安全性要求Access Token 有效期要短。
  • 用戶體驗要求:用戶不想頻繁地被強制重新登錄。

為了解決這個矛盾,Refresh Token 應運而生。

核心理念:雙 Token 認證系統

無感刷新機制的核心在于引入了兩種類型的 Token:

  1. Access Token(訪問令牌)

    • 用途:用于訪問受保護的 API 資源,附加在每個請求的 Header 中。
    • 特點:生命周期短(如 1 小時),無狀態,服務器無需存儲。
    • 存儲:通常存儲在客戶端內存中(如 Vuex/Redux),因為需要頻繁讀取。
  2. Refresh Token(刷新令牌)

    • 用途:當 Access Token 過期時,專門用于獲取一個新的 Access Token
    • 特點:生命周期長(如 7 天或 30 天),與特定用戶綁定,服務器需要安全存儲其有效性記錄。
    • 存儲:必須安全存儲。最佳實踐是存儲在 HttpOnly Cookie 中,這樣可以防止客戶端 JavaScript 腳本(如 XSS 攻擊)讀取它。

既然如此,為何不直接使用 Refresh Token 呢?

Access Token 通常是無狀態的,服務器無需記錄它,也導致 JWT 無法主動吊銷,而 Refresh Token 是有狀態的,服務器需要一個列表(數據庫中的“白名單”或“吊銷列表”)來記錄哪些 Refresh Token 是有效的,當用戶更改密碼、或從某個設備上“主動登出”時,服務器端可以主動將對應的 Refresh Token 設為無效。

無感刷新的詳細工作流

下面是這個“魔法”發生的具體步驟:

  1. 首次登錄:用戶使用用戶名和密碼登錄。服務器驗證成功后,返回一個 Access Token 和一個 Refresh Token
  2. 正常請求:客戶端將 Access Token 存儲起來,并在后續的每次 API 請求中,通過 Authorization 請求頭將其發送給服務器。
  3. Token 過期:當 Access Token 過期后,客戶端再次用它請求 API。服務器會拒絕該請求,并返回一個特定的狀態碼,通常是 401 Unauthorized
  4. 攔截 401 錯誤:客戶端的請求層(如 Axios 攔截器)會捕獲這個 401 錯誤。此時,它不會立即通知用戶“你已掉線”,而是暫停這個失敗的請求。
  5. 發起刷新請求:攔截器使用 Refresh Token 去調用一個專門的刷新接口(例如 /api/auth/refresh)。
  6. 處理刷新結果
    • 刷新成功:服務器驗證 Refresh Token 有效,生成一個新的 Access Token(有時也會返回一個新的 Refresh Token,這被稱為“刷新令牌旋轉”策略,可以提高安全性),并將其返回給客戶端。
    • 刷新失敗:如果 Refresh Token 也過期了或無效,服務器會返回錯誤(如 403 Forbidden)。這意味著用戶的登錄會話徹底結束。
  7. 重試與終結
    • 若刷新成功:客戶端用新的 Access Token 自動重發剛才失敗的那個 API 請求。用戶完全感覺不到任何中斷,數據操作無縫銜接。
    • 若刷新失敗:客戶端清除所有認證信息,強制用戶登出,并重定向到登錄頁面。

實戰演練:使用 Axios 攔截器實現無感刷新

Axios 的攔截器是實現這一流程的完美工具。下面是一個完整且考慮了并發問題的實現方案。

1. 創建 Axios 實例

首先,我們創建一個單獨的 Axios 實例,方便統一管理。

// a-pi/request.js
import axios from 'axios';

const service = axios.create({
 baseURL: '/api',
 timeout: 10000,
});

// 請求攔截器
service.interceptors.request.use(
 config => {
    // 在發送請求之前,從 state management (e.g., Vuex/Pinia/Redux) 獲取 token
    const accessToken = getAccessTokenFromStore(); 
    if (accessToken) {
      config.headers['Authorization'] = `Bearer ${accessToken}`;
    }
    return config;
  },
 error => {
    return Promise.reject(error);
  }
);

2. 核心:響應攔截器

這是實現無感刷新的關鍵。

// a-pi/request.js (續)

// 用于刷新 token 的 API
import { refreshTokenApi } from './auth'

let isRefreshing = false; // 控制刷新狀態的標志
let requests = []; // 存儲因 token 過期而掛起的請求

service.interceptors.response.use(
 response => response, // 對成功響應直接返回
 async error => {
    const { config, response: { status } } = error;
    
    // 1. 如果不是 401 錯誤,直接返回錯誤
    if (status !== 401) {
      return Promise.reject(error);
    }

    // 2. 避免重復刷新:如果正在刷新 token,將后續請求暫存
    if (isRefreshing) {
      return new Promise(resolve => {
        requests.push(() => resolve(service(config)));
      });
    }

    isRefreshing = true;

    try {
      // 3. 調用刷新 token 的 API
      const { newAccessToken } = await refreshTokenApi(); // 假設 refresh token 通過 HttpOnly cookie 自動發送

      // 4. 更新本地存儲的 access token
      setAccessTokenInStore(newAccessToken);
      
      // 5. 重試剛才失敗的請求
      config.headers['Authorization'] = `Bearer ${newAccessToken}`;
      
      // 6. 重新執行所有被掛起的請求
      requests.forEach(cb => cb());
      requests = []; // 清空隊列
      
      return service(config); // 返回重試請求的結果
    } catch (refreshError) {
      // 7. 如果刷新 token 也失敗了,則執行登出操作
      console.error('Unable to refresh token.', refreshError);
      logoutUser(); // 清除 token,重定向到登錄頁
      return Promise.reject(refreshError);
    } finally {
      isRefreshing = false;
    }
  }
);

export default service;

代碼解析:

  • 并發處理isRefreshing 標志和 requests 數組是關鍵。當第一個 401 錯誤觸發刷新時,isRefreshing 變為 true。后續在刷新完成前到達的 401 請求,都會被推進 requests 隊列中掛起,而不是重復發起刷新請求。當刷新成功后,再遍歷隊列,依次執行這些被掛起的請求。
  • 原子操作:通過這種“加鎖”機制,確保了刷新 Token 的操作是原子的,避免了資源浪費和潛在的競態條件。
  • 優雅降級:當 Refresh Token 也失效時,系統會執行 logoutUser(),進行清理工作并引導用戶重新登錄,這是一個優雅的失敗處理方案。

無感刷新 Token 機制是現代 Web 應用提升用戶體驗的“標配”。它將身份驗證的復雜性隱藏在后臺,為用戶提供了一個流暢、不間斷的操作環境。

實現這一機制,不僅僅是寫幾行代碼,更是對認證流程、安全性和用戶體驗三者之間平衡的深刻理解。


該文章在 2025/7/9 12:40:23 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
日本中文字幕一二区视频 | 中文字幕不卡免费精品视频 | 性开放网站在线网站在线 | 一本精品日本在线视频精品 | 一区二区免费不卡在线 | 亚洲午夜高清乱码中文字幕 |