最近在作一个后台管理系统,通常的后台系统都有权限管理这块,下面我就分享下我实现权限管理这块的思路。前端
首先说下这个系统前端用到的技术栈,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>
复制代码
生成的菜单以下:ide
我在网上查阅到的后台权限管理,都是跟角色挂钩的,没法知足个人需求,因而在反复思考下想到了这样的作法,有些不足的地方还须要继续补充和完善。例如:目前在菜单级别上,只是作了一二级菜单,没有三级菜单。在状态管理生成新的路由的代码片断感受写的有点繁琐,有待优化。但愿你们能提出意见。优化