最近在作一个后台管理系统,通常的后台系统都有权限管理这块,下面我就分享下我实现权限管理这块的思路。前端
首先说下这个系统前端用到的技术栈,vue全家桶,element-ui,axios。首先,用户的权限是经过前端来进行配置的,那么就须要一个页面去进行用户的权限配置。在用户登陆以后,经过请求后台查找该用户的权限信息,而后返回到前端。前端拿到权限信息以后,动态配置路由,再生成出对应的菜单列表。vue
毋庸置疑,权限是跟用户挂钩的。在用户管理页面,作一个受权页面。以下图: ios
export const homeRoute = { path: '/', component: index, redirect: '/home', children: [] }; export const routes = [ { path: '/home', component: home, icon: 'el-icon-home', index: '1', name: '系统首页', disabled: true }, { path: '/list', component: list, icon: 'el-icon-tickets', name: '菜单1', redirect: '/list1', index: '2', children: [ { path: '/list1', name: '菜单列表1', component: list1, index: '2-1' }, { path: '/list2', name: '菜单列表2', component: list2, index: '2-2' } ] }, { path: '/userManage', component: userManage, icon: 'el-icon-ticket', name: '用户管理', index: '3' } ]; 复制代码
首页默认是全部用户都能查看的。当为改用户勾选对应的菜单后,则会生成一个数组,存储着选中的菜单列表,如:['1', '2-1', '3', '2', '2-2']。element-ui
我在main.js文件作了以下配置:axios
var per = true; router.beforeEach((to, from, next) => { if (getStore('token') == null && to.path !== '/login') { next('/login'); } else { if (from.path !== '/login') { if (per) { store.dispatch('setPermList').then(() => { per = false; }); } else { next(); } } else { next(); } } next(); }); 复制代码
当页面每次刷新的时候(ps:定义per变量,就是为了防止每次进刷新的时候去dispatch,而是在页面刷新的时候去触发),去dispatch.状态管理的代码以下。首先拿到用户权限数组,而后分红一级菜单跟二级菜单两个数组。对一级菜单和默认的路由表进行遍历,筛选出有权限的路由表,再过滤掉一级路由里没有权限的二级路由。api
const state = { permList: [] }; const getters = { permList: state => state.permList }; const getters = { permList: state => state.permList }; const actions = { setPermList ({commit}) { return new Promise(resolve => { api.getUserPerm().then(res => { let perm = res.data; // 一级菜单 let oldParent = perm.filter(item => item.indexOf('-') < 0); // 一级菜单下的二级菜单 let child = perm.filter(item => item.indexOf('-') > 0); // for (let c of child) { // oldParent.push(c.split('-')[0]); // } child.map(c => { oldParent.push(c.split('-')[0]); }); console.log(child); let newParent = [...new Set(oldParent)]; // 去重 let routesList = [...new Set(routes)]; // 去重 let parentArray = []; // 生成一级菜单 newParent.map( item => { routesList.map( routesItem => { if (routesItem.index === item) { let it = Object.assign({}, routesItem); parentArray.push(it); } } ); } ); // 过滤掉一级菜单下的二级菜单 for (let pItem of parentArray) { pItem.children = pItem.children ? pItem.children.filter(n => child.indexOf(n.index) != -1) : null; } homeRoute.children = parentArray; router.addRoutes([homeRoute]); commit(types.PERM_LIST, parentArray); resolve(perm); }); }); } }; const mutations = { [types.PERM_LIST] (state, data) { state.permList = data; } }; 复制代码
例如,当获取到的用户权限为:['1', '2-1', '3'],那么生成的路由为:数组
{ path: '/home', component: home, icon: 'el-icon-home', index: '1', name: '系统首页', disabled: true }, { path: '/list', component: list, icon: 'el-icon-tickets', name: '菜单1', redirect: '/list1', index: '2', children: [ { path: '/list1', name: '菜单列表1', component: list1, index: '2-1' } ] }, { path: '/userManage', component: userManage, icon: 'el-icon-ticket', name: '用户管理', index: '3' } 复制代码
路由数组都出来了,那么生成菜单就不在话下了。菜单也是用到了element-ui的菜单bash
<div class="sidebar"> <!-- default-active:当前激活菜单的index ,collapse:是否折叠--> <el-menu class="sidebar-el-menu" :default-active="onRoutes" :collapse="collapse" background-color="#324157" text-color="#bfcbd9" active-text-color="#20a0ff" unique-opened router> <!--每一个菜单项--> <template v-for="item in permList"> <!--二级子菜单--> <template v-if="item.children"> <el-submenu :index="item.path" :key="item.path"> <template slot="title"> <i :class="item.icon"></i> <span slot="title">{{ item.name }}</span> </template> <template v-for="subItem in item.children"> <!--v-if,v-else:条件选择,加key属性会从新渲染--> <el-submenu v-if="subItem.children" :index="subItem.path" :key="subItem.path"> <template slot="title">{{ subItem.name }}</template> <el-menu-item v-for="(threeItem,i) in subItem.children" :key="i" :index="threeItem.path"> {{ threeItem.name }} </el-menu-item> </el-submenu> <!--没有三级子菜单,因此所有走else条件--> <el-menu-item v-else :index="subItem.path" :key="subItem.path"> {{ subItem.name }} </el-menu-item> </template> </el-submenu> </template> <template v-else> <el-menu-item :index="item.path" :key="item.path"> <i :class="item.icon"></i> <span slot="title">{{ item.name }}</span> </el-menu-item> </template> </template> </el-menu> </div> 复制代码
生成的菜单以下:markdown
我在网上查阅到的后台权限管理,都是跟角色挂钩的,没法知足个人需求,因而在反复思考下想到了这样的作法,有些不足的地方还须要继续补充和完善。例如:目前在菜单级别上,只是作了一二级菜单,没有三级菜单。在状态管理生成新的路由的代码片断感受写的有点繁琐,有待优化。但愿你们能提出意见。ide