Как избежать множественных запросов на обновление токена sh при одновременном выполнении запросов API с токеном с истекшим сроком действия - PullRequest
1 голос
/ 19 марта 2020

API-запрос с использованием JWT реализован в flask и Vue. js. JWT хранится в файле cook ie, и сервер проверяет JWT для каждого запроса.

Если срок действия токена истек, будет выдана ошибка 401. Если вы получили ошибку 401, обновите sh токен, как показано в приведенном ниже коде. Исходный запрос 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 возвращается с каждым запросом, каждый перехватчик обновляет sh токен.

Никакого вреда нет, но я не думаю, что это хороший способ. Есть хороший способ решить эту проблему.

Моя идея состоит в том, чтобы сначала сделать запрос API для проверки истечения срока действия токена. Этот метод состоит в том, чтобы после A проверять и обновлять * 1021 запросы A, B и C. * завершены. Поскольку файлы cookie являются HttpOnly, срок действия не может быть подтвержден на стороне клиента (JavaScript).

Извините, плохой английский sh ...

1 Ответ

1 голос
/ 19 марта 2020

Что вам нужно сделать, это поддерживать некоторое состояние вне перехватчика. Что-то, что говорит

Подожди, я в процессе получения нового токена.

Это лучше всего сделать, сохранив ссылку на Promise. Таким образом, первый перехватчик 401 может создать обещание, а затем все остальные запросы могут его ожидать.

const 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)
})
...