在网上看了很多教程,写的很乱,代码也没有给全。通过对比多篇博客,最终整理出了这篇文章,详细介绍了修改的过程。
源码在这个项目里:https://github.com/zouquchen/lecture-system/tree/master/vue-admin-template
vue模板:vue-admin-template-4.4.0
根据当前登录用户的角色信息生成对应的菜单栏。
比如,student可以查看到的菜单栏:
admin可以查看的菜单栏:
可以最后读这部分内容加深对角色权限路由的理解
项目中的路由均写在src\router\index.js
中,其中默认包含constantRoutes
,这就是我们需要解析的固定路由,无论用户的角色是什么,都需要显示这些路由内容。
export const constantRoutes = [
...
]
为了根据权限动态的生成路由,我们需要添加asyncRoutes
,这里面的内容将根据用户角色权限会动态生成。
export const asyncRoutes = [
...
]
在src\store\modules\permission.js
中,通过分析asyncRoutes
里面的角色权限和当前用户所拥有的角色权限,生成用户可查看到的路由列表permission_routes
。
在src\layout\components\Sidebar\index.vue
中,遍历permission_routes
显示菜单栏。
前端的每一个请求的操作之前都会获取的用户信息,获取用户的用户名(name)、头像(avatar)和角色(roles)。
项目默认只需要name和avatar,现在我们添加了角色roles。
此时获取用户的响应是这样的。
{
"msg":"成功",
"code":20000,
"roles":["admin"],
"name":"admin",
"avatar":"http://www.weixintouxiang.cn/weixin/20140607090832328.gif"
}
要修改以下7个文件:
文件名 | 修改方式 | 作用 |
---|---|---|
src\router\index.js | 修改 | 路由设置 |
src\store\modules\user.js | 修改 | 获取角色信息 |
src\store\modules\permission.js | 增加 | 根据角色解析路由 |
src\store\getters.js | 修改 | VUEX的Getters |
src\store\index.js | 修改 | 设置所需的VUEX模块 |
src\permission.js | 修改 | 权限逻辑修改 |
src\layout\components\Sidebar\index.vue | 修改 | 侧边栏解析修改 |
src\router\index.js
固定路由的写法,不需要任何权限,所有角色都可以访问。
/**
* 不需要任何权限,所有角色都可以访问
*/
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/index',
hidden: true,
children: [{
path: 'index',
component: () => import('@/views/index/index')
}]
}
]
需要我们添加的地方,根据权限显示的路由
export const asyncRoutes = [
{
path: '/webManage',
component: Layout,
meta: { roles: ['admin'] },
children: [
{
path: 'index',
name: '网站管理',
component: () => import('@/views/webManage/index'),
meta: { title: '网站管理', icon: 'cog-fill' }
}
]
},
// 404 页面必须放置在最后一个页面
{ path: '*', redirect: '/404', hidden: true }
]
通过修改meta
属性中roles
只有admin角色可以查看:
meta: { roles: ['admin'] }
admin和manager都可以查看
meta: { roles: ['admin', 'manager] }
注意:{ path: '*', redirect: '/404', hidden: true }
必须放在最后面,并且只能放在asyncRoutes
中,如果放在constantRoutes
中的话,刷新页面会报404。
src\store\modules\user.js
修改以下部分:
src\store\modules\permission.js
添加该文件:
import { asyncRoutes, constantRoutes } from '@/router'
/**
* Use meta.role to determine if the current user has permission
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
// 这个地方维护了两个状态一个是addRouters,一个是routes
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
src\store\getters.js
修改以下部分:
src\permission.js
替换以下文件:
import router, { constantRoutes } from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
const { roles } = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
router.options.routes = constantRoutes.concat(accessRoutes)
router.addRoutes(accessRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
src\layout\components\Sidebar\index.vue
修改以下内容:
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />