Skip to content

Commit 441ddd9

Browse files
committed
fix(view): 侧边栏权限管理
1 parent 0f3032f commit 441ddd9

File tree

5 files changed

+135
-29
lines changed

5 files changed

+135
-29
lines changed

admin/src/permission.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import getPageTitle from '@/utils/get-page-title'
88

99
NProgress.configure({ showSpinner: false }) // NProgress Configuration
1010

11-
const whiteList = ['/login', '/index', '/line', '/home', '/404', '/', '', '/echarts', '/md', '/out', '/excel', '/upload'] // 不重定向白名单
11+
const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
1212

1313
router.beforeEach(async(to, from, next) => {
1414
// start progress bar
@@ -26,15 +26,26 @@ router.beforeEach(async(to, from, next) => {
2626
next({ path: '/' })
2727
NProgress.done()
2828
} else {
29-
const hasGetUserInfo = store.getters.name
30-
if (hasGetUserInfo) {
29+
// determine whether the user has obtained his permission roles through getInfo
30+
const hasRoles = store.getters.roles && store.getters.roles.length > 0
31+
if (hasRoles) {
3132
next()
3233
} else {
3334
try {
3435
// get user info
35-
await store.dispatch('user/getInfo')
36+
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
37+
const { roles } = await store.dispatch('user/getInfo')
3638

37-
next()
39+
// generate accessible routes map based on roles
40+
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
41+
42+
// dynamically add accessible routes
43+
router.addRoutes(accessRoutes)
44+
console.log(router)
45+
46+
// hack method to ensure that addRoutes is complete
47+
// set the replace: true, so the navigation will not leave a history record
48+
next({ ...to, replace: true })
3849
} catch (error) {
3950
// remove token and go to login page to re-login
4051
await store.dispatch('user/resetToken')

admin/src/router/index.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,17 @@ export const routeSuper = [
199199

200200
]
201201

202+
const routeTest = [
203+
// 404 page must be placed at the end !!!
204+
{ path: '*', redirect: '/404', hidden: true }
205+
]
206+
207+
/**
208+
* asyncRoutes
209+
* the routes that need to be dynamically loaded based on user roles
210+
*/
211+
export const asyncRoutes = [...routeAdmin, ...routeSuper, ...routeTest]
212+
202213
// 基础路由
203214
const routeBase = [
204215
{ path: '/', name: 'index', component: () => import('@/views/home/index'), hidden: true },
@@ -228,17 +239,17 @@ const routeBase = [
228239
}
229240
]
230241

231-
const routeTest = [
232-
// 404 page must be placed at the end !!!
233-
{ path: '*', redirect: '/404', hidden: true }
234-
]
235-
236-
export const constantRouterMap = [...routeAdmin, ...routeSuper, ...routeBase, ...routeTest]
242+
/**
243+
* constantRoutes
244+
* a base page that does not have permission requirements
245+
* all roles can be accessed
246+
*/
247+
export const constantRoutes = [...routeBase]
237248

238249
const createRouter = () => new Router({
239250
// mode: 'history', // require service support
240251
scrollBehavior: () => ({ y: 0 }),
241-
routes: constantRouterMap
252+
routes: constantRoutes
242253
})
243254

244255
const router = createRouter()

admin/src/store/index.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
import Vue from 'vue'
22
import Vuex from 'vuex'
33
import getters from './getters'
4-
import app from './modules/app'
5-
import settings from './modules/settings'
6-
import user from './modules/user'
74

85
Vue.use(Vuex)
96

7+
// https://webpack.js.org/guides/dependency-management/#requirecontext
8+
const modulesFiles = require.context('./modules', true, /\.js$/)
9+
10+
// you do not need `import app from './modules/app'`
11+
// it will auto require all vuex module from modules file
12+
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
13+
// set './app.js' => 'app'
14+
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
15+
const value = modulesFiles(modulePath)
16+
modules[moduleName] = value.default
17+
return modules
18+
}, {})
19+
1020
const store = new Vuex.Store({
11-
modules: {
12-
app,
13-
settings,
14-
user
15-
},
21+
modules,
1622
getters
1723
})
1824

admin/src/store/modules/permission.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { asyncRoutes, constantRoutes } from '@/router'
2+
3+
/**
4+
* Use meta.role to determine if the current user has permission
5+
* @param roles
6+
* @param route
7+
*/
8+
function hasPermission(roles, route) {
9+
if (route.meta && route.meta.roles) {
10+
return roles.some(role => route.meta.roles.includes(role))
11+
} else {
12+
return true
13+
}
14+
}
15+
16+
/**
17+
* Filter asynchronous routing tables by recursion
18+
* @param routes asyncRoutes
19+
* @param roles
20+
*/
21+
export function filterAsyncRoutes(routes, roles) {
22+
const res = []
23+
24+
routes.forEach(route => {
25+
const tmp = { ...route }
26+
if (hasPermission(roles, tmp)) {
27+
if (tmp.children) {
28+
tmp.children = filterAsyncRoutes(tmp.children, roles)
29+
}
30+
res.push(tmp)
31+
}
32+
})
33+
34+
return res
35+
}
36+
37+
const state = {
38+
routes: [],
39+
addRoutes: []
40+
}
41+
42+
const mutations = {
43+
SET_ROUTES: (state, routes) => {
44+
state.addRoutes = routes
45+
state.routes = constantRoutes.concat(routes)
46+
}
47+
}
48+
49+
const actions = {
50+
generateRoutes({ commit }, roles) {
51+
return new Promise(resolve => {
52+
let accessedRoutes
53+
if (roles.includes('Super Administrator')) {
54+
accessedRoutes = asyncRoutes || []
55+
} else {
56+
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
57+
}
58+
commit('SET_ROUTES', accessedRoutes)
59+
resolve(accessedRoutes)
60+
})
61+
}
62+
}
63+
64+
export default {
65+
namespaced: true,
66+
state,
67+
mutations,
68+
actions
69+
}

admin/src/store/modules/user.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import { getToken, setToken, removeToken } from '@/utils/auth'
44
const state = {
55
token: getToken(),
66
name: '',
7-
avatar: ''
7+
avatar: '',
8+
roles: [],
9+
addRouters: []
810
}
911

1012
const mutations = {
@@ -45,15 +47,22 @@ const actions = {
4547
getInfo({ commit, state }) {
4648
return new Promise((resolve, reject) => {
4749
getInfo(state.token).then(response => {
48-
const data = response.data
49-
if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
50-
commit('SET_ROLES', data.roles)
51-
} else {
52-
reject('getInfo: roles must be a non-null array !')
50+
const { data } = response
51+
52+
if (!data) {
53+
reject('Verification failed, please Login again.')
5354
}
54-
commit('SET_NAME', data.name)
55-
commit('SET_AVATAR', data.avatar)
56-
resolve(response)
55+
56+
const { roles, name, avatar } = data
57+
// roles must be a non-empty array
58+
if (!roles || roles.length <= 0) {
59+
reject('getInfo: roles must be a non-null array!')
60+
}
61+
62+
commit('SET_NAME', name)
63+
commit('SET_AVATAR', avatar)
64+
commit('SET_ROLES', roles)
65+
resolve(data)
5766
}).catch(error => {
5867
reject(error)
5968
})

0 commit comments

Comments
 (0)