在 Vue.js 中捕获和重定向 JWT 令牌过期,而不阻塞 Vue 3 中的其他 401 错误

Posted

技术标签:

【中文标题】在 Vue.js 中捕获和重定向 JWT 令牌过期,而不阻塞 Vue 3 中的其他 401 错误【英文标题】:Catching and redirecting JWT token expiration in Vue.js without blocking other 401 errors in Vue 3 【发布时间】:2021-08-29 19:04:31 【问题描述】:

我无法让两件事一起工作——关于我的 axios 承诺捕获错误的方式中的竞争条件?以下是详细信息:

(1) 当用户的 JWT 令牌过期时,我的 API 返回 401,并且 axios 拦截路由用户注销。

main.js

createApp(App)
    .use(store)
    .use(router)
    .mount('#app')

routes.js

import axios from "axios";
import createRouter, createWebHistory from 'vue-router'
const routes = [
  
    path: '/',
    name: 'Home',
    component: Home,
    meta: requiresAuth: false
,..]
...
const router = createRouter(
  history: createWebHistory(process.env.BASE_URL),
  routes
)

axios.interceptors.response.use(response => 
    return response;
, error => 
    if (error.response.status === 401) 
        console.log('token expired',error.response)
        /* THIS WORKS BUT BREAKS THE LOGIN ERROR HANDLING */

    
    return Promise.reject(error);
);

这可行,但它会中断:

(2) 如果用户使用错误的凭据登录,服务器登录 API 也会返回 401,并且我的应用会显示错误消息。

LogInUser.vue

methods: 
    login() 
      this.$store
        .dispatch('login', 
          username: this.username,
          password: this.password
        )
        .then(() => 
          this.$router.push( name: 'EventList' )
        )
        .catch(err => 
          console.log(err)
          this.error = err.response.data.detail
        )
    
  

在我的 Vuex 商店中 store.js

login( commit , credentials) 
  return axios
    .post('//localhost:9000/api/login/', credentials)
    .then(( data ) => 
      commit('SET_LOGIN_DATA', data)
    )

我可以让一个或另一个工作(正确处理登录错误,或正确处理 JWT 令牌到期错误),但不能同时工作。 axios 拦截器尝试先到达那里并尝试将用户路由到注销,然后一切都搞砸了。任何想法我做错了什么?

【问题讨论】:

【参考方案1】:

我已经解决了一个类似的问题(也许是一样的?),方法是将我的拦截器设置为一个接受 router 参数的函数并在我的路由上使用元数据,如下所示:

Interceptor.js

export default router => 
    // In your interceptor error handler callback
    if (is401 && router.currentRoute.meta.requiresAuth === true) 
        // Redirect to logout
    

ma​​in.js

import registerInterceptor from './path/to/interceptor.js'

// Initialize router and other stuff

// Register the interceptor in created() lifecycle method
new Vue(
  router,
  store,
  created () 
    registerInterceptor(this.$router)
  ,
  render: h => h(App)
).$mount('#app')

然后,当我定义我的路线时,我会添加一个 meta 属性,如下所示:

// Some routes

    path: '/secure-route',
    name: 'secureRoute',
    component: ...,
    meta: 
        requiresAuth: true
    

然后拦截器仅在路由需要身份验证时才会重定向。您可以反转它并将元属性命名为skipLogoutRedirect,并在您的拦截器中仅重定向skipLogoutRedirect === false,因此您不必在所有安全路由上定义新的meta.requiresAuth: true,而只需定义meta.skipLogoutRedirect: true on您的登录路线。

如果这还不够清楚,请告诉我,我可以尝试添加更多细节。

【讨论】:

谢谢——我知道这是正确的做法,并为我的路由添加了身份验证属性,但由于某种原因,我无法在拦截处理程序中访问router.currentRoute.meta.requiresAuth。 >TypeError:无法读取未定义的属性“requiresAuth” 你是如何初始化路由器然后设置你的拦截器的? 我刚刚更新了答案。再次查看main.js 部分,看看是否可以修复它。我刚刚意识到我最初并没有包含那个细节。 嗨!我用我的初始化方式更新了 q 。我使用的是 Vue 3 语法,这让我感到困惑,我是如何使用新的 Vue 3 初始化样式编写的。 你的拦截器需要在它自己的文件中定义。然后无论你挂载 Vue 应用程序本身,你都可以调用该拦截器函数并传递路由器实例。 或者看起来你应该可以使用router,因为你的拦截器是在下面创建router的地方定义的。

以上是关于在 Vue.js 中捕获和重定向 JWT 令牌过期,而不阻塞 Vue 3 中的其他 401 错误的主要内容,如果未能解决你的问题,请参考以下文章

jwt令牌过期后如何注销

当令牌在角度4中过期时如何重定向到注销

使用过期令牌发出同时 API 请求时如何避免多个令牌刷新请求

如果刷新(JWT)令牌未经授权(401响应),AngularJS重定向到登录

在 JWT 刷新时出现 401 时重定向

如何在 Vue JS 中处理登录 JWT 令牌?