我有一个简单的用例,其中我的应用程序使用vue-router
和vuex
。然后,store
包含一个user
对象,该对象在开始时是null
。从服务器验证用户后,它将发送回一个user
对象,该对象包含JWT
auth令牌,该对象将分配给商店中的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商店中添加一个加载标志,然后将商店导入到路由器中即可。老实说,尽管我不会打扰,但在不错的生产服务器上,支票将很快完成,以至于用户不太可能看到它。
尝试vue.js mixins
您可以定义全局混合物并通过Vue.use(myMixin)
使用它 - 然后所有组件都将继承此Mixin。如果您定义了mounted
或Mixin上的activated
挂钩,则将在每个组件上调用。
在那里您可以使用组件可以做的所有事情-this
将指向您的组件。如果组件也定义了钩子本身,则相同类型的混合钩将在之前运行
或尝试单个顶级登录组件
我们使用了一些不同的解决方案 - 我们有一个单个组件,该组件可以处理所有与登录相关的内容,该组件存在于路由器视图之外的parent index.html中。该组件始终处于活动状态,可以隐藏DIV路由器视图并叠加加载消息或登录屏幕。对于Intranet应用程序,只要浏览器保持开放,该组件也将使用轮询来保持会话的生命。
您可以将路由器 - 游动装置加载到此组件上。 - 因此,想要触发路由器 - 游动的儿童组件只是设置了由顶级身份验证组件观看的全局反应性属性navigateTo
。这将触发身份验证检查,可能是登录工作流,之后,顶级组件将使用此方法调用$router.push()
,您可以完全控制任何导航。
您可以在某些请求时使用interceptors
默默获取auth令牌。
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);
});
由于使用vuex
,因此可以添加一些状态,例如isLoading
或isChecking
。
和在router.beforeEach
中,您可以检查并设置isLoading
或isChecking
遵循当前检查状态。然后,您可以显示加载消息,请遵循此状态。
在我们的路线中。 不是。
路线
{
path: '/dashboard',
name: dashboard,
meta: {
layout: 'home-layout'
},
components: {
default: Dashboard,
header: UserHeader
},
beforeEnter: ifAuthenticated,
}
路线
const ifAuthenticated = (to, from, next) => {
if (localStorage.getItem(token)) {
next();
return;
}
router.push({
name: 'login',
params: {
returnTo: to.path,
query: to.query,
},
});
};