【问题标题】:Refresh JWT Token using Axios request interceptor (interceptors.request) - Multiple requests at once problem使用 Axios 请求拦截器 (interceptors.request) 刷新 JWT Token - 一次多个请求的问题
【发布时间】:2021-01-29 06:54:19
【问题描述】:

我正在使用此代码拦截 Axios 中的每个 HTTP 调用,以便通过在 JWT 令牌过期时刷新来保持用户登录:

const { token } = window.localStorage;

const axiosInstance = axios.create({
    baseURL: process.env.VUE_APP_API_ENDPOINT,
    withCredentials: false,
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
      Authorization: token && token.length > 0 ? `Bearer ${token}` : ""
    }
  });

axiosInstance.interceptors.request.use(request => {
    if (request.url.endsWith("refresh")) {  // prevent infinite loop
      return request;
    }

const { expiryDate } = window.localStorage;
const currentTimestamp = Math.round(new Date().getTime() / 1000);

if (expiryDate && currentTimestamp >= expiryDate) {
  console.log("token expired.");

  return store
    .dispatch("auth/refreshToken")  // refreshToken action will place the token in localStorage.token
    .then(() => {
      const newToken = window.localStorage.token; 

      request.headers.Authorization = `Bearer ${newToken}`;

      return Promise.resolve(request);
    })
    .catch(() => Promise.resolve(request));
}
console.log("token not expired.");

return request;

});

这在我在页面加载时添加更多请求之前一直工作正常,每个请求都试图刷新导致后端错误的令牌。我该如何解决这个问题?我搜索了很多,但我找到的所有解决方案都是针对interceptors.responselike this one,我想使用interceptors.request,因为登录是可选的,如果用户未登录,则不会有 401 响应。

编辑:根据下面用户 28 的回答,代码已更改为:

axiosInstance.interceptors.request.use(async config => {
    if (config.url.endsWith("refresh")) {
      // if we are making a refresh token call, return it to prevent infinite loop
      return config;
    }

    await axiosInstance.refreshingToken;

    const { expiryDate } = window.localStorage; // token expiry date

    const currentTimestamp = Math.round(new Date().getTime() / 1000);

    if (expiryDate && currentTimestamp >= expiryDate) {
      axiosInstance.refreshingToken = store.dispatch("auth/refreshToken"); // this will update the token in localstorage
      await axiosInstance.refreshingToken;
    }

    const { token } = window.localStorage; // grab the token from localstorage

    config.headers.Authorization = `Bearer ${token}`;

    return config;
  });

【问题讨论】:

    标签: javascript vue.js axios vuex


    【解决方案1】:

    您需要一个全局变量来确定您是否必须等待。最简单的方法是将其分配给 axios 实例。

    示例代码:

    axios.interceptors.request.use(async config => {
      if (isRefreshTokenRequest) {
        return config
      }
    
      if (axios.refreshingToken) {
        await axios.refreshingToken
      }
    
      if (isTokenExpired) {
        axios.refreshingToken = store.dispatch('auth/refreshToken')
        await axios.refreshingToken
      }
    
      // set authorization header
    
      return config
    })
    

    【讨论】:

    • 我更新了代码以使用这种方法,但是,它仍然发送超过 1 个刷新令牌请求,我有一个 Vue 组件在 mounted() 中触发 3 个请求,并且所有三个都发送刷新令牌请求到导致问题的 API,因为 API 在刷新完成后会从数据库中删除刷新令牌。感谢您的帮助。
    • @GreenTrain 啊,这是我的错。见this。打开 DevTools 并查看日志和网络请求。
    • 我改变的是在await axios.refreshingToken添加一个新的if条件。起初我认为即使 refreshingToken 未定义也应该没问题。但它使代码异步,因此第二个请求无法获得从第一个请求设置的refreshingToken 的值。添加if条件后,第一个请求将通过同步设置refreshingToken
    猜你喜欢
    • 2020-01-13
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2021-01-23
    • 2019-12-31
    • 2017-08-22
    • 2022-11-14
    • 1970-01-01
    相关资源
    最近更新 更多