首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Axios拦截器和异步登录

Axios拦截器和异步登录
EN

Stack Overflow用户
提问于 2016-03-10 02:54:53
回答 2查看 54.4K关注 0票数 45

我正在我的web应用程序中实现令牌身份验证。我的access token每隔N分钟过期一次,然后使用refresh token登录并获取新的access token

我所有的API调用都使用Axios。我设置了一个拦截器来拦截401响应。

代码语言:javascript
复制
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等)。

我该如何确保语句在promise返回之前不会执行?

(在github上有一个相应的问题:https://github.com/mzabriskie/axios/issues/266)

EN

回答 2

Stack Overflow用户

发布于 2016-03-19 00:06:50

只需使用另一个承诺:D

代码语言:javascript
复制
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;
    });
});

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

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

代码语言:javascript
复制
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

票数 32
EN

Stack Overflow用户

发布于 2018-04-12 10:16:23

可以在请求中这样做,而不是在响应中,而且可能会更干净,因为它可以避免在访问令牌过期时访问服务器。从this article复制

代码语言:javascript
复制
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);
});

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35900230

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档