在 Vue.js 中捕获并重定向 JWT 令牌过期,而不会阻止 Vue 3 中的其他 401 错误
Catching and redirecting JWT token expiration in Vue.js without blocking other 401 errors in Vue 3
我无法让两件事一起工作——我的 axios 承诺捕获错误的方式中的竞争条件?详情如下:
(1) 当用户的 JWT 令牌过期时,我的 APIs return 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 也会 return 出现 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 拦截尝试首先到达那里并尝试将用户路由到注销,然后一切都搞砸了。知道我做错了什么吗?
我解决了一个类似的问题(也许是一样的?),方法是将我的拦截器设置为一个接受 router
参数的函数,并在我的路由上使用元数据,如下所示:
Interceptor.js
export default router => {
// In your interceptor error handler callback
if (is401 && router.currentRoute.meta.requiresAuth === true) {
// Redirect to logout
}
}
main.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
并且在您的拦截器中只需重定向 if skipLogoutRedirect === false
,这样您就不必在所有安全上定义新的 meta.requiresAuth: true
路线,而只在您的登录路线上定义 meta.skipLogoutRedirect: true
。
如果这还不够清楚,请告诉我,我可以尝试添加更多细节。
我无法让两件事一起工作——我的 axios 承诺捕获错误的方式中的竞争条件?详情如下:
(1) 当用户的 JWT 令牌过期时,我的 APIs return 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 也会 return 出现 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 拦截尝试首先到达那里并尝试将用户路由到注销,然后一切都搞砸了。知道我做错了什么吗?
我解决了一个类似的问题(也许是一样的?),方法是将我的拦截器设置为一个接受 router
参数的函数,并在我的路由上使用元数据,如下所示:
Interceptor.js
export default router => {
// In your interceptor error handler callback
if (is401 && router.currentRoute.meta.requiresAuth === true) {
// Redirect to logout
}
}
main.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
并且在您的拦截器中只需重定向 if skipLogoutRedirect === false
,这样您就不必在所有安全上定义新的 meta.requiresAuth: true
路线,而只在您的登录路线上定义 meta.skipLogoutRedirect: true
。
如果这还不够清楚,请告诉我,我可以尝试添加更多细节。