Axios interceptors and asynchronous login

試著忘記壹切 提交于 2019-11-26 15:19:39

问题


I'm implementing token authentication in my web app. My access token expires every N minutes and than a refresh token is used to log in and get a new access token.

I use Axios for all my API calls. I have an interceptor set up to intercept 401 responses.

axios.interceptors.response.use(undefined, function (err) {
  if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
    serviceRefreshLogin(
      getRefreshToken(),
      success => { setTokens(success.access_token, success.refresh_token) },
      error => { console.log('Refresh login error: ', error) }
    )
    err.config.__isRetryRequest = true
    err.config.headers.Authorization = 'Bearer ' + getAccessToken()
    return axios(err.config);
  }
  throw err
})

Basically, as I intercept a 401 response, I want to do a login and than retry the original rejected request with the new tokens. My serviceRefreshLogin function calls setAccessToken() in its then block. But the problem is that the then block happens later than the getAccessToken() in the interceptor, so the retry happens with the old expired credentials.

getAccessToken() and getRefreshToken() simply return the existing tokens stored in the browser (they manage localStorage, cookies, etc).

How would I go about ensuring statements do not execute until a promise returns?

(Here's a corresponding issue on github: https://github.com/mzabriskie/axios/issues/266)


回答1:


Just use another promise :D

axios.interceptors.response.use(undefined, function (err) {
    return new Promise(function (resolve, reject) {
        if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
            serviceRefreshLogin(
                getRefreshToken(),
                success => { 
                        setTokens(success.access_token, success.refresh_token) 
                        err.config.__isRetryRequest = true
                        err.config.headers.Authorization = 'Bearer ' + getAccessToken();
                        axios(err.config).then(resolve, reject);
                },
                error => { 
                    console.log('Refresh login error: ', error);
                    reject(error); 
                }
            );
        }
        throw err;
    });
});

If your enviroment doesn't suport promises use polyfill, for example https://github.com/stefanpenner/es6-promise

But, it may be better to rewrite getRefreshToken to return promise and then make code simpler

axios.interceptors.response.use(undefined, function (err) {

        if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
            return getRefreshToken()
            .then(function (success) {
                setTokens(success.access_token, success.refresh_token) ;                   
                err.config.__isRetryRequest = true;
                err.config.headers.Authorization = 'Bearer ' + getAccessToken();
                return axios(err.config);
            })
            .catch(function (error) {
                console.log('Refresh login error: ', error);
                throw error;
            });
        }
        throw err;
});

Demo https://plnkr.co/edit/0ZLpc8jgKI18w4c0f905?p=preview




回答2:


Could do it in the request instead of the response, and it'd probably be cleaner since it'd avoid hitting the server when the access token's expired. Copying from this article:

function issueToken() {
  return new Promise((resolve, reject) => {
    return client({
      ...
    }).then((response) => {
      resolve(response);
    }).catch((err) => {
      reject(err);
    });
  });
}

client.interceptors.request.use((config) => {
  let originalRequest = config;
  if (tokenIsExpired && path_is_not_login) {
    return issueToken().then((token) => {
      originalRequest['Authorization'] = 'Bearer ' + token;
      return Promise.resolve(originalRequest);
    });
  }
  return config;
}, (err) => {
  return Promise.reject(err);
});


来源:https://stackoverflow.com/questions/35900230/axios-interceptors-and-asynchronous-login

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!