1. 路由拦截
vue项目中通常都是通过配置routes配置项来控制路由跳转,例如设置
routes:[
{
path:'cinema',
redirect:'/page/cinema',
component: BlankLayout,
meta:{title:'影院',requiresAuth:true},
children:[
{
path:'cinema/plan' ,
name:'cinmeapPlan',
component:()=>import('./view/cinema/plan')
meta:{title:'影院排期'}
},
{
path:'cinema/cinemaDetail' ,
name:'cinemaDetail',
component:()=>import('./view/cinema/cinemaDetail')
meta:{title:'影院详情'}
},
]
}]
利用routes中的meta属性添加一个字段,用作标识,首先在router.js的文件中定义router,具体如下:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({ routes })
export router
接着在下面文件中结合路由守卫,进行登陆验证,另外如果用户登录成功之后,token会默认放在vuex中的getters中,所以在导航守卫中判断对应getters是否存在,如果存在,证明用户已登录,允许用户进入该路由。否则就跳转登陆页,并把当前页的路由座位query参数传递给login页面:
to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title}`))
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.token) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
if (to.query.siteCode) {
next()
return
}
if (from.query.siteCode) {
const query = JSON.parse(JSON.stringify(to.query))
query.siteCode = from.query.siteCode
next({
path: to.path,
query: query
})
} else {
next() // 确保一定要调用 next()
}
}
}
这里为什么要遍历to.matched数组判断meta的requiresAuth字段,而不是直接使用使用to.matched.requiresAuth来判断,首先例子中给的是cinema,一级路由设置了requiresAuth,而cinemaPlan没有设置。假设有两种情况:
前提:vue路由匹配时会同时匹配满足情况的所有路由,即如果路由是/cineme/plan的话,/cinema也会触发。另外如果较高等级的路由需要控制的话,它所有的嵌套路由基本都是需要控制的。
- cinema具有登陆控制,cinemaPlan没有,如果用户点击路由跳转的话,它必然是先进入一级路由,再去二级路由,一级路由实现登陆控制,利用to.meta是能够满足的。注意这里是正常点击,但是如果用户通过改变url的话去访问cinemaPlan的话,则需要给cinemaPlan路由添加requiresAuth字段,同理也需要给requiresAuth添加字段,如果路由比较多的话,就很麻烦
- cinema没有登陆控制,而cinemaPlan有,这种情况确实不怕用户改变url访问二级路由了,但是二级路由过多,也是需要设置许多requiresAuth。
所以,为了方便,直接遍历to.matched数组,该数组保存着匹配到的所有路由信息。就该例而言,访问cinema时,matched数组长度为1,访问cinemaplan时,matched数组长度为2,即保存着/cinema,以及/cinema/plan,其实啰嗦了这么直接使用to.meta字段判断也可以,就是需要给所有需要控制路由添加requiresAuth,to.matched则只需要给较高的一级添加requiresAuth,其下所有的子路由都不必添加
2.axios拦截器
当前token失效了,但是token依然保存在本地,这时候你去访问需要权限的路由时,实际上应该让用户重新登陆。这时候就需要结合http拦截器+后端接口返回的http状态码来判断
// http request拦截器
axios.interceptors.request.use(
config =>{
if(store.state.token){ //判断是否存在token,如果存在的话,则每个http header都加上token
config.header.Authorization = `token ${store.state.token}`;
}
return config
},
err=>{
return Promise.reject(err);
}
)
// http reponse拦截器
axios.interceptors.response.use(response=>{
return response,
},
error=>{
if(error.reponse){
switch(error.reponse.status){
case 401:
store.commit(types.LOGOUT)
router.currentRoute.name !== 'login' && router.replace({
path: 'login',
query: {redirect: router.currentRoute.fullPath}
}
}
return promise.reject(error.reponse.data);
}
)