最近在做一个后台管理系统,一般的后台系统都有权限管理这块,下面我就分享下我实现权限管理这块的思路。
首先说下这个系统前端用到的技术栈,vue全家桶,element-ui,axios。首先,用户的权限是通过前端来进行配置的,那么就需要一个页面去进行用户的权限配置。在用户登录之后,通过请求后台查找该用户的权限信息,然后返回到前端。前端拿到权限信息之后,动态配置路由,再生成出对应的菜单列表。
毋庸置疑,权限是跟用户挂钩的。在用户管理页面,做一个授权页面。如下图:
树结构用的是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’]。
我在main.js文件做了如下配置:
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.状态管理的代码如下。首先拿到用户权限数组,然后分成一级菜单跟二级菜单两个数组。对一级菜单和默认的路由表进行遍历,筛选出有权限的路由表,再过滤掉一级路由里没有权限的二级路由。
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的菜单
生成的菜单如下:
我在网上查阅到的后台权限管理,都是跟角色挂钩的,无法满足我的需求,于是在反复思考下想到了这样的做法,有些不足的地方还需要继续补充和完善。例如:目前在菜单级别上,只是做了一二级菜单,没有三级菜单。在状态管理生成新的路由的代码片段感觉写的有点繁琐,有待优化。希望大家能提出意见,想要看源码的可以私聊我。原文地址:https://juejin.im/post/5c08c3ece51d451dde1b0c08