業務場景---Token無感重新整理

最小生成树發表於2024-07-27

業務場景描述

假設使用者正在填寫一個複雜的表單,由於表單內容繁多,使用者花費了很長時間才填完。這時,如果Token已經過期,系統會讓使用者重新登入,這種體驗顯然是非常糟糕的。為了避免這種情況,我們需要在Token即將過期或已經過期時,自動重新整理Token,而不影響使用者正在進行的操作。

技術實現思路

一、準備工作

  1. 前端框架選擇:本文以Vue.js為例,結合Vue Router和Axios來實現Token無感重新整理機制。
  2. 後端支援:後端需要提供重新整理Token的介面,當接收到舊的Token時返回一個新的Token。

二、關鍵技術點

  1. 攔截請求:使用Axios攔截器來檢測每一個請求的狀態,如果發現Token過期,則觸發重新整理Token的邏輯。
  2. 重新整理Token:實現一個專門用於重新整理Token的方法,該方法會在舊的Token過期時自動呼叫並更新Token。
  3. 請求佇列:在重新整理Token期間,暫停其他需要Token的請求,待Token重新整理成功後,重新傳送這些請求。

三、具體實現步驟

1. 配置Axios攔截器

首先,配置Axios攔截器來檢測請求和響應的狀態,並在Token過期時觸發重新整理Token的邏輯。

import axios from 'axios';
import store from './store'; // 假設使用Vuex來管理全域性狀態
import router from './router';

let isRefreshing = false;
let requests = [];

axios.interceptors.request.use(
  config => {
    const token = store.state.token;
    if (token) {
      config.headers['Authorization'] = 'Bearer ' + token;
    }
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

axios.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    const { config, response } = error;
    const originalRequest = config;
    
    if (response && response.status === 401) {
      if (!isRefreshing) {
        isRefreshing = true;
        return refreshToken().then(newToken => {
          store.commit('setToken', newToken);
          originalRequest.headers['Authorization'] = 'Bearer ' + newToken;
          processQueue(null, newToken);
          return axios(originalRequest);
        }).catch(err => {
          processQueue(err, null);
          store.commit('logout');
          router.push('/login');
          return Promise.reject(err);
        }).finally(() => {
          isRefreshing = false;
        });
      } else {
        return new Promise((resolve, reject) => {
          requests.push((token) => {
            originalRequest.headers['Authorization'] = 'Bearer ' + token;
            resolve(axios(originalRequest));
          });
        });
      }
    }
    return Promise.reject(error);
  }
);

function processQueue(error, token = null) {
  requests.forEach(promise => {
    if (error) {
      promise.reject(error);
    } else {
      promise.resolve(token);
    }
  });
  requests = [];
}

2. 實現重新整理Token的方法

接下來,實現一個用於重新整理Token的方法refreshToken。這個方法會呼叫後端介面來獲取新的Token。

function refreshToken() {
  return new Promise((resolve, reject) => {
    axios.post('/auth/refresh', {
      refreshToken: store.state.refreshToken
    }).then(response => {
      if (response.data.success) {
        resolve(response.data.token);
      } else {
        reject(response.data.message);
      }
    }).catch(error => {
      reject(error);
    });
  });
}

3. 更新Vuex狀態管理

確保在Vuex中有相關的狀態和方法來管理Token和使用者登入狀態。

const store = new Vuex.Store({
  state: {
    token: localStorage.getItem('token') || '',
    refreshToken: localStorage.getItem('refreshToken') || '',
    user: {}
  },
  mutations: {
    setToken(state, token) {
      state.token = token;
      localStorage.setItem('token', token);
    },
    setRefreshToken(state, refreshToken) {
      state.refreshToken = refreshToken;
      localStorage.setItem('refreshToken', refreshToken);
    },
    logout(state) {
      state.token = '';
      state.refreshToken = '';
      state.user = {};
      localStorage.removeItem('token');
      localStorage.removeItem('refreshToken');
    }
  }
});

4. 處理登入邏輯

確保在使用者登入時,正確地儲存Token和重新整理Token。

function login(credentials) {
  return axios.post('/auth/login', credentials).then(response => {
    store.commit('setToken', response.data.token);
    store.commit('setRefreshToken', response.data.refreshToken);
  });
}

總結:當使用者在填寫複雜表單時,即使Token過期也不會中斷他們的操作,從而提供了更好的使用者體驗。這個機制不僅適用於表單填寫,還可以廣泛應用於任何需要長時間互動的Web應用場景中。

相關文章