繁体   English   中英

Axios拦截器和异步登录

[英]Axios interceptors and asynchronous login

我正在我的网络应用程序中实现令牌身份验证。 我的access token每N分钟到期,而refresh token用于登录并获取新的access token

我使用Axios进行所有API调用。 我有一个拦截器设置拦截401响应。

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

基本上,当我拦截401响应时,我想进行登录,然后使用新令牌重试原始被拒绝的请求。 我的serviceRefreshLogin函数在其then块中调用setAccessToken() 但问题是then块发生的时间晚于拦截器中的getAccessToken() ,因此使用旧的过期凭据进行重试。

getAccessToken()getRefreshToken()只返回存储在浏览器中的现有标记(它们管理localStorage,cookies等)。

在承诺返回之前,我将如何确保语句不会执行?

(这是github上的相应问题: https//github.com/mzabriskie/axios/issues/266

只是使用另一个承诺: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;
    });
});

如果您的环境不支持承诺使用polyfill,例如https://github.com/stefanpenner/es6-promise

但是,重写getRefreshToken以返回promise然后使代码更简单可能更好

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;
});

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

可以在请求而不是响应中执行此操作,并且它可能更清晰,因为它会在访问令牌过期时避免命中服务器。 这篇文章中复制:

 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); }); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM