簡體   English   中英

使用過期令牌同時發出 API 請求時如何避免多個令牌刷新請求

[英]How to avoid multiple token refresh requests when making simultaneous API requests with an expired token

使用 JWT 的 API 請求在 Flask 和 Vue.js 中實現。 JWT 存儲在 cookie 中,服務器為每個請求驗證 JWT。

如果令牌已過期,將返回 401 錯誤。 如果您收到 401 錯誤,請按照以下代碼刷新令牌,再次發出原始 API 請求。 以下代碼適用於所有請求。

http.interceptors.response.use((response) => {
    return response;
}, error => {
    if (error.config && error.response && error.response.status === 401 && !error.config._retry) {
        error.config._retry = true;
        http
            .post(
                "/token/refresh",
                {},
                {
                    withCredentials: true,
                    headers: {
                        "X-CSRF-TOKEN": Vue.$cookies.get("csrf_refresh_token")
                    }
                }
            )
            .then(res => {
                if (res.status == 200) {
                    const config = error.config;
                    config.headers["X-CSRF-TOKEN"] = Vue.$cookies.get("csrf_access_token");
                    return Axios.request(error.config);
                }
            })
            .catch(error => {

            });
    }
    return Promise.reject(error);
});

在令牌過期的情況下同時發出多個 API 請求時,無用地刷新令牌。 例如,請求 A、B 和 C 幾乎同時執行。 由於每次請求都會返回 401,因此每個攔截器都會刷新令牌。

沒有真正的傷害,但我認為這不是一個好方法。 有一個很好的方法可以解決這個問題。

我的想法是先做一個API請求來驗證token過期,這個方法是在驗證和刷新完成之后再做請求A、B、C。 由於 cookie 是 HttpOnly,因此無法在客戶端 (JavaScript) 驗證到期日期。

對不起,英語不好...

您需要做的是在攔截器之外維護一些狀態。 說的東西

等等,我正在獲取新令牌。

這最好通過保留對Promise的引用來完成。 這樣,第一個 401 攔截器可以創建承諾,然后所有其他請求都可以等待它。

let refreshTokenPromise // this holds any in-progress token refresh requests

// I just moved this logic into its own function
const getRefreshToken = () => http.post('/token/refresh', {}, {
  withCredentials: true,
  headers: { 'X-CSRF-TOKEN': Vue.$cookies.get('csrf_refresh_token') }
}).then(() => Vue.$cookies.get('csrf_access_token'))

http.interceptors.response.use(r => r, error => {
  if (error.config && error.response && error.response.status === 401) {
    if (!refreshTokenPromise) { // check for an existing in-progress request
      // if nothing is in-progress, start a new refresh token request
      refreshTokenPromise = getRefreshToken().then(token => {
        refreshTokenPromise = null // clear state
        return token // resolve with the new token
      })
    }

    return refreshTokenPromise.then(token => {
      error.config.headers['X-CSRF-TOKEN'] = token
      return http.request(error.config)
    })
  }
  return Promise.reject(error)
})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM