Vue 资源拦截器刷新 JWT 令牌

Posted

技术标签:

【中文标题】Vue 资源拦截器刷新 JWT 令牌【英文标题】:Vue resource interceptor to refresh JWT token 【发布时间】:2021-05-17 11:46:07 【问题描述】:

我正在尝试编写一个 vue-resource 拦截器来刷新 JWT 访问令牌,当它过期时。我假设我需要一个请求后回调来检查令牌过期错误(在我的情况下为status == 401),然后调用刷新端点并重试初始请求。

使用下面的代码,我面临的唯一问题是刷新令牌后的next() 调用永远不会发生,即使刷新执行良好并且新令牌保存到localStorage

Vue.http.interceptors.push(function (request, next) 

    if (!request.headers.has('Authorization') && window.localStorage.access_token) 
        request.headers.set('Authorization', `Bearer $window.localStorage.access_token`);
    

    next(function (response) 
        if (response.status === 401) 
            const refreshToken = localStorage.getItem('refresh_token');

            Vue.http.post('/api/v4/auth/refresh', null, 
                headers: 'Authorization': `Bearer $refreshToken`
            ).then((response) => 
                localStorage.setItem('access_token', response.data.accessToken);
                localStorage.setItem('refresh_token', response.data.refreshToken);
            ).then(() => 
                next();
            );
        
    );
)

【问题讨论】:

【参考方案1】:

我认为回调的链接不太正确。对 next 的第二次调用应该在第一次调用返回一个 Promise 时发生,并且不应依赖于用于解决第一个 Promise 的逻辑,而仅取决于该 Promise 的成功解决。

Vue.http.interceptors.push(function (request, next) 

  if (!request.headers.has('Authorization') && window.localStorage.access_token) 
    request.headers.set('Authorization', `Bearer $window.localStorage.access_token`);
  

  next(function (response) 
    if (response.status === 401) 
        const refreshToken = localStorage.getItem('refresh_token');

        return Vue.http.post('/api/v4/auth/refresh', null, 
            headers: 'Authorization': `Bearer $refreshToken`
        ).then((response) => 
            localStorage.setItem('access_token', response.data.accessToken);
            localStorage.setItem('refresh_token', response.data.refreshToken);
        )
    
    return Promise.resolve(response)
  ).then(() => 
     next(); // This is called whenever the first callback returns a promise
  );
)

【讨论】:

应用您建议的更改时,我收到TypeError: next(...).then is not a function. 不确定到底是什么问题?我的猜测是当response.status 没有Promise 附加then 到?即使这可行,我仍然怀疑第二次简单地调用next() 是行不通的。我不确定在第二次 next() 调用中是否以及如何修改 response 对象。 我的错。如果状态为 200,第一次调用应该会解决承诺。我已经编辑了我的答案。最后一点,为什么要在第二次调用 next() 时修改响应? 我认为return Promise.resolve(...)return Vue.http.post 的值都不会传播到next() 堆栈。这意味着我的拦截器调用next() 并在HTTP 调用完成后传递一个要在response 对象上执行的函数。但是,这个函数的结果似乎被忽略了。

以上是关于Vue 资源拦截器刷新 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章

Angular 4.3 - HTTP 拦截器 - 刷新 JWT 令牌

Axios 拦截器不会在页面加载时拦截

委托刷新令牌获取新JWT的基本策略

如何在jwt中过期时刷新令牌

当 jwt 刷新令牌未过期时,React Native 应用程序注销

JWT 令牌失效的未知原因