项目源码地址:GitHub - PanJiaChen/vue-admin-template: a vue2.0 minimal admin template
注意:项目中的路由均写在 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 显示菜单栏。
配置步骤
1、在 src\router\index.js 文件中
固定路由的写法,不需要任何权限,所有角色都可以访问
/*** 固定路由* 没有权限要求的基页* 所有角色都可以访问*/
export const constantRoutes = [{path: '/login',component: () => import('@/views/login/index'),hidden: true},{path: '/404',component: () => import('@/views/404'),hidden: true},{path: '/dashboard',component: () => import('@/views/dashboard/index'),hidden: true}/* {path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import('@/views/dashboard/index'),meta: { title: '首页' }}]} */
]
动态路由的写法,需要我们添加的地方,根据权限显示的路由
/*** 异步路由* 需要根据用户角色动态加载的路由*/
export const asyncRoutes = [// 用户端 start{path: '/rescueActivity',redirect: '/rescueActivity',component: Layout,meta: { roles: ['user'] },children: [{path: '/rescueActivity',name: 'rescueActivity',component: () => import('@/views/user/rescue-activity'),meta: { title: '志愿救助活动' }}]},// 用户端 end// 管理员端 start{path: '/userManage',redirect: '/userManage',component: Layout,meta: { roles: ['admin'] },children: [{path: '/userManage',name: 'userManage',component: () => import('@/views/admin/user-manage'),meta: { title: '用户管理' }}]},// 管理员端 end// 404页一定要放在最后!!!{ path: '*', redirect: '/404', hidden: true }
]
通过修改 meta 属性中 roles 值
只有 admin 角色可以查看:meta: { roles: ['admin'] }
admin 和 user 都可以查看:meta: { roles: ['admin', 'user'] }
注意:{ path: '*', redirect: '/404', hidden: true } 必须放在最后面,并且只能放在 asyncRoutes 中,如果放在 constantRoutes 中的话,刷新页面会报 404 错误
2、在 src\store\modules\user.js 文件中
① 在 getDefaultState 里面的 avatar: '', 后面添加 roles: [] 值,如图:
roles: []
② 在 mutations 里面的 SET_AVATAR: (state, avatar) => { state.avatar = avatar }, 后面添加 SET_ROLES: (state, roles) => { state.roles = roles } 值,如图:
SET_ROLES: (state, roles) => {state.roles = roles
}
③ 在 getInfo 方法里面的 commit('SET_AVATAR', avatar) 后面添加 commit('SET_ROLES', roles) 值,如图:
const { name, avatar, roles } = data
commit('SET_ROLES', roles)
④ 在 logout、resetToken 方法里面的 commit('RESET_STATE') 后面添加 commit('SET_ROLES', []) 值,如图:
commit('SET_ROLES', [])
3、添加 src\store\modules\permission.js 文件
在 src\store\modules 目录下面没有 permission.js 文件,需要添加
permission.js
import { asyncRoutes, constantRoutes } from '@/router'/*** 使用 meta.role 来确定当前用户是否具有权限* @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}
}/*** 通过递归过滤异步路由表* @param routes 异步路由* @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,一个是routesstate.addRoutes = routesstate.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
}
4、在 src\store\getters.js 文件中
在 getters 里面的 name: state => state.user.name, 后面添加 roles: state => state.user.roles, permission_routes: state => state.permission.routes 值,如图:
roles: state => state.user.roles,
permission_routes: state => state.permission.routes
5、将 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 Configurationconst whiteList = ['/login'] // no redirect whitelistrouter.beforeEach(async(to, from, next) => {// start progress barNProgress.start()// set page titledocument.title = getPageTitle(to.meta.title)// determine whether the user has logged inconst hasToken = getToken()if (hasToken) {if (to.path === '/login') {// if is logged in, redirect to the home pagenext({ path: '/' })NProgress.done()} else {const hasRoles = store.getters.roles && store.getters.roles.length > 0if (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 rolesconst accessRoutes = await store.dispatch('permission/generateRoutes', roles)// dynamically add accessible routesrouter.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 recordnext({ ...to, replace: true })} catch (error) {// remove token and go to login page to re-loginawait 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 directlynext()} 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 barNProgress.done()
})
6、在 src\layout\components\Sidebar\index.vue 文件中
将原来的 <sidebar-item ... /> 替换掉
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
在 ...mapGetters 里面的 'sidebar', 后面添加 'permission_routes' 值,如图:
'permission_routes'
7、在 src\store\index.js 文件中
在 import user from './modules/user' 下面添加 import permission from './modules/permission' 导入 permission 值;在 new Vuex.Store 里面的 user, 后面添加 permission 值,如图:
import permission from './modules/permission'
permission