在路由进入 Vue 路由器之前检查身份验证令牌是否有效
Checking auth token valid before route enter in Vue router
我有一个简单的用例,我的应用程序使用 vue-router
和 vuex
。然后 store
包含一个 user
对象,它在开头是 null
。从服务器验证用户后,它发回一个 user
对象,其中包含一个 JWT
授权令牌,该令牌分配给商店中的 user
对象。现在假设用户在 3 小时后回来并尝试访问路线或执行任何其他操作,考虑到届时身份验证令牌已过期,最好的检查方法是什么(需要调用 axios post
进行检查)并将用户重定向到 login
页面。我的应用程序将包含大量组件,因此我知道我可以编写逻辑来检查每个组件的 mounted
挂钩中的令牌是否有效,但这意味着重复所有组件。此外,我不想使用 beforeEach
导航守卫,因为我无法向用户显示任何视觉反馈,如 checking...
或 loading...
.
我在我的一个项目中做了类似的事情,处理这些类型的情况实际上看起来很困难,但你可以在你的受保护路由中添加一个 beforeEnter
守卫,然后在身份验证失败时重定向。
const guard = function(to, from, next) {
// check for valid auth token
axios.get('/api/checkAuthToken').then(response => {
// Token is valid, so continue
next();
}).catch(error => {
// There was an error so redirect
window.location.href = "/login";
})
};
然后在你的路线上你可以做:
{
path: '/dashboard',
component: Dashboard,
beforeEnter: (to, from, next) => {
guard(to, from, next);
}
},
您可能会注意到我使用了 location.href
而不是 router.push
。我这样做是因为我的登录表单受 csrf 保护,所以我需要一个新的 csrf_token。
您的另一个问题是,如果用户试图在不更改路由的情况下与您的页面进行交互(即他们单击按钮并获得 401 响应)。为此,我发现最简单的方法是检查每个 axios
请求的身份验证,并在收到 401 响应时重定向到 login
。
就在防护检查期间添加加载微调器而言,您可以简单地向 vuex 存储添加一个加载标志,然后将您的存储导入路由器。老实说,虽然我不会打扰,但在一个像样的生产服务器上,检查将完成得如此之快,以至于用户不太可能看到它。
当某些请求发生时,您可以使用 interceptors
静默获取身份验证令牌。
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const rToken = window.localStorage.getItem('rToken');
return axios.post('url/to/get/refresh/token', { rToken })
.then(({data}) => {
window.localStorage.setItem('token', data.token);
window.localStorage.setItem('rToken', data.refreshToken);
axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
return axios(originalRequest);
});
}
return Promise.reject(error);
});
尝试Vue.JSMixins
您可以定义一个全局 Mixin 并通过 Vue.use(myMixin)
使用它 - 然后所有组件都将继承此 mixin。如果你在 mixin 上定义了一个 mounted
或可能更好的 activated
钩子,它会在每个组件上被调用。
在那里您可以使用组件可以做的一切 - this
将指向您的组件。并且如果组件本身也定义了一个钩子,相同类型的mixin钩子将运行 在组件自己的钩子之前。
或尝试单个顶级登录组件
我们使用了一个稍微不同的解决方案——我们有一个单独的组件来处理所有与登录相关的事情,它存在于父 index.html 的路由器视图之外。该组件始终处于活动状态,可以隐藏 div 路由器视图并覆盖加载消息或登录屏幕。对于 Intranet 应用程序,只要浏览器保持打开状态,此组件还将使用轮询来保持会话处于活动状态。
您可以将路由器导航加载到此组件。 - 因此,想要触发路由器导航的子组件只需设置一个全局反应 属性 navigateTo
,它由顶级身份验证组件监视。这将触发身份验证检查,可能是登录工作流,之后顶级组件将调用 $router.push()
使用这种方法,您可以完全控制任何导航。
因为您使用 vuex
,您可以添加一些状态,例如 isLoading
或 isChecking
。
并且在您的 router.beforeEach
中,您可以检查并设置 isLoading
或 isChecking
按照您当前的检查状态。然后你可以显示加载信息按照这个状态。
In our route.js we check in beforeEnter hooks the user has token or
not.
route.js
{
path: '/dashboard',
name: dashboard,
meta: {
layout: 'home-layout'
},
components: {
default: Dashboard,
header: UserHeader
},
beforeEnter: ifAuthenticated,
}
route.js
const ifAuthenticated = (to, from, next) => {
if (localStorage.getItem(token)) {
next();
return;
}
router.push({
name: 'login',
params: {
returnTo: to.path,
query: to.query,
},
});
};
我有一个简单的用例,我的应用程序使用 vue-router
和 vuex
。然后 store
包含一个 user
对象,它在开头是 null
。从服务器验证用户后,它发回一个 user
对象,其中包含一个 JWT
授权令牌,该令牌分配给商店中的 user
对象。现在假设用户在 3 小时后回来并尝试访问路线或执行任何其他操作,考虑到届时身份验证令牌已过期,最好的检查方法是什么(需要调用 axios post
进行检查)并将用户重定向到 login
页面。我的应用程序将包含大量组件,因此我知道我可以编写逻辑来检查每个组件的 mounted
挂钩中的令牌是否有效,但这意味着重复所有组件。此外,我不想使用 beforeEach
导航守卫,因为我无法向用户显示任何视觉反馈,如 checking...
或 loading...
.
我在我的一个项目中做了类似的事情,处理这些类型的情况实际上看起来很困难,但你可以在你的受保护路由中添加一个 beforeEnter
守卫,然后在身份验证失败时重定向。
const guard = function(to, from, next) {
// check for valid auth token
axios.get('/api/checkAuthToken').then(response => {
// Token is valid, so continue
next();
}).catch(error => {
// There was an error so redirect
window.location.href = "/login";
})
};
然后在你的路线上你可以做:
{
path: '/dashboard',
component: Dashboard,
beforeEnter: (to, from, next) => {
guard(to, from, next);
}
},
您可能会注意到我使用了 location.href
而不是 router.push
。我这样做是因为我的登录表单受 csrf 保护,所以我需要一个新的 csrf_token。
您的另一个问题是,如果用户试图在不更改路由的情况下与您的页面进行交互(即他们单击按钮并获得 401 响应)。为此,我发现最简单的方法是检查每个 axios
请求的身份验证,并在收到 401 响应时重定向到 login
。
就在防护检查期间添加加载微调器而言,您可以简单地向 vuex 存储添加一个加载标志,然后将您的存储导入路由器。老实说,虽然我不会打扰,但在一个像样的生产服务器上,检查将完成得如此之快,以至于用户不太可能看到它。
当某些请求发生时,您可以使用 interceptors
静默获取身份验证令牌。
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const rToken = window.localStorage.getItem('rToken');
return axios.post('url/to/get/refresh/token', { rToken })
.then(({data}) => {
window.localStorage.setItem('token', data.token);
window.localStorage.setItem('rToken', data.refreshToken);
axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
return axios(originalRequest);
});
}
return Promise.reject(error);
});
尝试Vue.JSMixins
您可以定义一个全局 Mixin 并通过 Vue.use(myMixin)
使用它 - 然后所有组件都将继承此 mixin。如果你在 mixin 上定义了一个 mounted
或可能更好的 activated
钩子,它会在每个组件上被调用。
在那里您可以使用组件可以做的一切 - this
将指向您的组件。并且如果组件本身也定义了一个钩子,相同类型的mixin钩子将运行 在组件自己的钩子之前。
或尝试单个顶级登录组件
我们使用了一个稍微不同的解决方案——我们有一个单独的组件来处理所有与登录相关的事情,它存在于父 index.html 的路由器视图之外。该组件始终处于活动状态,可以隐藏 div 路由器视图并覆盖加载消息或登录屏幕。对于 Intranet 应用程序,只要浏览器保持打开状态,此组件还将使用轮询来保持会话处于活动状态。
您可以将路由器导航加载到此组件。 - 因此,想要触发路由器导航的子组件只需设置一个全局反应 属性 navigateTo
,它由顶级身份验证组件监视。这将触发身份验证检查,可能是登录工作流,之后顶级组件将调用 $router.push()
使用这种方法,您可以完全控制任何导航。
因为您使用 vuex
,您可以添加一些状态,例如 isLoading
或 isChecking
。
并且在您的 router.beforeEach
中,您可以检查并设置 isLoading
或 isChecking
按照您当前的检查状态。然后你可以显示加载信息按照这个状态。
In our route.js we check in beforeEnter hooks the user has token or not.
route.js
{
path: '/dashboard',
name: dashboard,
meta: {
layout: 'home-layout'
},
components: {
default: Dashboard,
header: UserHeader
},
beforeEnter: ifAuthenticated,
}
route.js
const ifAuthenticated = (to, from, next) => {
if (localStorage.getItem(token)) {
next();
return;
}
router.push({
name: 'login',
params: {
returnTo: to.path,
query: to.query,
},
});
};