后台鉴权 & 动态路由+颗粒化权限
# 后台鉴权 & 动态路由+颗粒化权限
参考教程:
[TOC]
# 一、动态路由-实现思路
# 1.1 登录完成后的行为
# 1.1.1 路由钩子获取动态路由信息
在全局钩子router.beforeEach
中拦截路由。
# 1.1.1.1 正常跳转
判断是否获取了动态路由信息,存在则不获取路由。
# 1.1.1.2 刷新页面
刷新页面肯定会丢失Vuex
,所以重新获取动态路由。
# 1.1.2 递归解析后端路由
# 1.1.3 通过addRouter
与基本路由信息进行拼接
创建vue
实例的时候将vue-router
挂载,但这个时候vue-router
挂载一些登录或者不用权限的公用的页面。
# 1.1.4 存储到Vuex,用于侧边栏显示
# 二、动态路由
动态添加更多的路由规则。参数必须是一个符合 routes
选项要求的数组。
router.addRoutes(routers: Array<RouteConfig>)
1
# 2.1 routes
interface RouteConfig = {
path: string,
component?: Component,
name?: string, // 命名路由
components?: { [name: string]: Component }, // 命名视图组件
redirect?: string | Location | Function,
props?: boolean | Object | Function,
alias?: string | Array<string>,
children?: Array<RouteConfig>, // 嵌套路由
beforeEnter?: (to: Route, from: Route, next: Function) => void,
meta?: any,
// 2.6.0+
caseSensitive?: boolean, // 匹配规则是否大小写敏感?(默认值:false)
pathToRegexpOptions?: Object // 编译正则的选项
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2.2 具体实现
# 2.2.1 转换 - 将后端返回来的值转成vue能识别的路由
function addRouter(routerlist) {
const router = []
try {
routerlist.forEach(e => {
if (e.path && e.component) {
let e_new = {
path: e.path,
name: e.path,
}
if (e.children) {
const children = addRouter(e.children)
// 保存权限
e_new = {
...e_new,
children: children
}
}
if (e.is_show === 2) {
e_new = {
...e_new,
hidden: true
}
} else {
e_new = {
...e_new,
component: () => import(`@/views/${e.component}`)
}
}
if (e.icon !== '' && e.name !== '') {
e_new = {
...e_new,
meta: {
title: e.name,
icon: e.icon
}
}
} else if (e.name !== '' && e.icon === '') {
e_new = {
...e_new,
meta: {
title: e.name
}
}
}
router.push(e_new)
}
})
} catch (error) {
console.error(error)
return []
}
return router
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 转换前(后端)
[{
path: '/pluginMgt',
component: 'layout/Layout',
name: '运营分析',
icon: 'database',
is_show: 1,
children: [{
path: 'index',
component: 'index',
name: '账号分析',
is_show: 1,
icon: '',
}]
}]
// 转换后(前端)
[{
path: '/pluginMgt',
component: 'layout/Layout',
name: '运营分析',
icon: 'database',
is_show: 1,
children: [{
path: 'index',
component: 'pluginMgt/index',
name: '账号分析',
is_show: 1,
icon: '',
}]
}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 2.2.2 拼接 - router.addRoutes
let last = [{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},{
path: '*',
redirect: '/404',
hidden: true
}]
asyncRouter = asyncRouter.concat(last)
router.addRoutes(asyncRouter) // vue-router提供的addRouter方法进行路由拼接
store.dispatch('setRouterList', asyncRouter) // 存储到vuex
store.commit('set_init', true) // 避免再次发起请求
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
actions: {
// 动态设置路由 此为设置途径
setRouterList({
commit
}, routerList) {
commit('set_router', StaticRouterMap.concat(routerList)) // 进行路由拼接并存储
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
const StaticRouterMap = [{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/',
component: Layout,
name: 'index',
children: [{
path: '/',
name: 'index',
component: () => import('@/views/index/index'),
meta: {
title: '首页',
icon: 'home_defualt'
}
}]
},
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2.2.3 整体流程
if (user.state.init) {
// 获取了动态路由 data一定true,就无需再次请求 直接放行
next()
} else {
// data为false,一定没有获取动态路由,就跳转到获取动态路由的方法
gotoRouter(to, next)
}
function gotoRouter(to, next) {
getUserMenu(store.getters.token) // 获取动态路由的方法
.then(res => {
const asyncRouter = addRouter(res.data) // 进行递归解析
return asyncRouter
})
.then(asyncRouter => {
let last = [{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '*',
redirect: '/404',
hidden: true
}
]
asyncRouter = asyncRouter.concat(last)
router.addRoutes(asyncRouter) // vue-router提供的addRouter方法进行路由拼接
console.log(asyncRouter)
store.dispatch('setRouterList', asyncRouter) // 存储到vuex
store.commit('set_init', true)
next({
...to,
replace: true
}) // hack方法 确保addRoutes已完成
})
.catch(e => {
console.log(e)
removeToken()
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 三、颗粒化权限
# 3.1 实现思路
/**
* @export 自定义指令
*/
export function directive() {
Vue.directive('permit', {
bind(el, binding) {
// 一行三目运算符就可
// return store.getters.roleTest.includes(binding.value)
!store.getters.roleTest.includes(binding.value) ? el.parentNode.removeChild(el) : {}
}
})
}
// roleTest: [1]
// v-permit="1"
// <el-button v-permit="1" type="primary">增加</el-button> 显示
// <el-button v-permit="2" type="primary">增加</el-button> 不显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
actions: {
// 存储颗粒化权限
setroles({
commit
}, roleList) {
commit('SET_ROLES', roleList)
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
// 需要引入到main.js
import { directive } from './utils/directive'
// ....
directive()
// ....
1
2
3
4
5
2
3
4
5