一、登录页面
this.$store.dispatch('LoginByEmail', this.loginForm).then(() => {
this.$router.push({ path: '/' }); //登录成功之后重定向到首页
}).catch(err => {
this.$message.error(err); //登录失败提示错误
});
二、vuex中异步触发的actions LoginByEmail的处理内容如下
LoginByEmail ({ commit }, userInfo) {
const email = userInfo.email.trim()
return new Promise((resolve, reject) => {
loginByEmail(email, userInfo.password).then(response => {
const data = response.data
setToken(response.data.token)
commit('SET_TOKEN', data.token)
resolve()
}).catch(error => {
reject(error)
})
})
}
三、具体代码
router.beforeEach((to, from, next) => {
if (getToken()) { // 判断是否取到token
if (to.path === '/login') {
next({ path: '/' })
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已获取完user_info信息
store.dispatch('GetInfo').then(res => { // 获取user_info
const roles = res.data.role
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to }) // 放行路由
})
}).catch(() => {
store.dispatch('FedLogOut').then(() => {
next({ path: '/login' })
})
})
} else {
next() // 放行该路由
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单里的路径,继续让其访问
next()
} else { // 其他不在白名单里的路径全部让其重定向到登录页面!
next('/login')
alert('not in white list, now go to the login page')
}
}
})
四、具体实现
1.router.js
// router.js
import Vue from 'vue';
import Router from 'vue-router';
import Login from '../views/login/';
const dashboard = resolve => require(['../views/dashboard/index'], resolve);
//使用了vue-routerd的[Lazy Loading Routes
](https://router.vuejs.org/en/advanced/lazy-loading.html)
//所有权限通用路由表
//如首页和登录页和一些不用权限的公用页面
export const constantRouterMap = [
{ path: '/login', component: Login, hidden: true //hidden为自定义属性,侧边栏那章会纤细解释},
{
path: '/',
component: Layout,
redirect: '/dashboard',
name: '首页',
children: [{ path: 'dashboard', component: dashboard }]
},
]
//实例化vue的时候只挂载constantRouter
export default new Router({
routes: constantRouterMap
});
//异步挂载的路由
//动态需要根据权限加载的路由表
export const asyncRouterMap = [
{
path: '/permission',
component: Layout,
redirect: '/permission/index',
name: '权限测试',
meta: { role: ['admin','super_editor'] }, //页面需要的权限
children: [
{
path: 'index',
component: Permission,
name: '权限测试页',
meta: { role: ['admin','super_editor'] } //页面需要的权限
}]
},
{ path: '*', redirect: '/404', hidden: true }
];
2.main.js
// main.js
router.beforeEach((to, from, next) => {
if (store.getters.token) { // 判断是否有token
if (to.path === '/login') {
next({ path: '/' });
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(res => { // 拉取info
const roles = res.data.role;
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next(to); // hack方法 确保addRoutes已完成
})
}).catch(err => {
console.log(err);
});
} else {
next() //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的全面会自动进入404页面
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next();
} else {
next('/login'); // 否则全部重定向到登录页
}
}
});
五、登录逻辑如图
重构之前权限判断代码
上面一张图就是在使用addRoutes方法之前的权限判断,非常的繁琐,因为我是把所有的路由都挂在了上去,所有我要各种判断当前的用户是否有权限进入该页面,各种if/else的嵌套,维护起来相当的困难。但现在有了addRoutes之后就非常的方便,我只挂载了用户有权限进入的页面,没权限,路由自动帮我跳转的404,省去了不少的判断。
这里还有一个小hack的地方,就是router.addRoutes之后的next()可能会失效,因为可能next()的时候路由并没有完全add完成,好在查阅文档发现
next('/') or next({ path: '/' }): redirect to a different location. The current navigation will be aborted and a new one will be started.
这样我们就可以简单的通过next(to)巧妙的避开之前的那个问题了。