最近在作一個後臺管理系統,通常的後臺系統都有權限管理這塊,下面我就分享下我實現權限管理這塊的思路。前端
首先說下這個系統前端用到的技術棧,vue全家桶,element-ui,axios。首先,用戶的權限是經過前端來進行配置的,那麼就須要一個頁面去進行用戶的權限配置。在用戶登陸以後,經過請求後臺查找該用戶的權限信息,而後返回到前端。前端拿到權限信息以後,動態配置路由,再生成出對應的菜單列表。vue
毋庸置疑,權限是跟用戶掛鉤的。在用戶管理頁面,作一個受權頁面。以下圖: ios
樹結構用的是element-ui裏面的樹形控件。生成這個樹形菜單的數據源爲前端配置好的默認的路由表。'icon'爲菜單對應的圖表,'index'爲自定義的索引,用來配合這個樹形控件生成權限信息。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>
複製代碼
生成的菜單以下:ide
我在網上查閱到的後臺權限管理,都是跟角色掛鉤的,沒法知足個人需求,因而在反覆思考下想到了這樣的作法,有些不足的地方還須要繼續補充和完善。例如:目前在菜單級別上,只是作了一二級菜單,沒有三級菜單。在狀態管理生成新的路由的代碼片斷感受寫的有點繁瑣,有待優化。但願你們能提出意見。優化