最近在作一個後臺管理系統,通常的後臺系統都有權限管理這塊,下面我就分享下我實現權限管理這塊的思路。前端
首先說下這個系統前端用到的技術棧,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