前言
管理后台权限控制是使用了RBAC模型,前端是vue,后端是eggjs。
RBAC(Role-Based Access Control)模型是一种用于访问控制的权限管理模型。
在 RBAC 模型中,权限的分配和管理是基于角色进行的。
RBAC 模型包含用户(User),角色(Role),权限(Permission)
表设计
权限表permissions
角色表roles及其用户-角色中间表,角色-权限中间表
管理后台配置权限页面效果
权限管理列表:
这里需要手动把所有路由和权限 按层级录入,这里后端需要提供一个查询组装好的树结构的接口
角色管理列表:
这里可以创建角色相关信息,然后给角色 权限配置和成员管理
权限配置,给该角色勾选权限码提交
成员管理,给该角色勾选用户提交
后端接口实现
这里使用eggjs框架,用egg-sequelize作为ORM库。相关model表关联实现,角色表roles查询 角色的权限配置和获取用户权限getUserInfo方法 看我之前的文章:
sequelize多对多关联实现
这里补充一下其他相关
// 角色表roles删除方法,需要把中间表关联数据删除
async del() {
const { ctx, app } = this;
const reqBody = ctx.request.body;
const model = ctx.model.Roles;
const { id } = reqBody;
try {
// 查找该元数据
const exitItem = await model.findOne({
where: { id }
});
if (!exitItem) {
return ctx.error(4002, '当前数据不存在');
}
// 记录删除人操作信息
await exitItem.update({
updateUser: ctx.userInfo.id,
updateUserName: ctx.userInfo.username,
});
// 删除所有关联数据
exitItem.setPermissions([])
// 删除
await exitItem.destroy();
ctx.success({ id });
} catch (error) {
ctx.error(4002, error);
}
}
权限表permissions没复杂接口,都是常规的增删改查
// 权限表permissions 数据的组装成 树结构
async getTreelist() {
const { ctx, app } = this;
const model = ctx.model.Permissions;
const { type } = query;
const tableQuery = {
raw: true,
where: {
type: type || 'admin'
},
attributes: {
exclude: ['deleted_at']
}
};
try {
const data = await model.findAll(tableQuery);
const convertToTree = (arr, parentId = null) => {
const result = [];
for (const item of arr) {
if (item.parentId === parentId) {
const children = convertToTree(arr, item.id);
result.push({
...item,
children
});
}
}
return result;
};
const tree = convertToTree(data);
ctx.success(tree);
} catch (error) {
ctx.error(4002, error);
}
}
登录通过getUserInfo方法返回了所有权限码,前端vue项目在路由拦截器上判断,第一次初始化时获取用户信息接口后,根据router.addRoutes方法把成功匹配的路由动态增加。按钮级别的权限码在页面上用v-permission自定义指令校验,下面是vue的自定义指令实现
// 路径 src/directive/permission.js
import { hasPermission } from '@/utils/auth'
// 权限控制指令
async function checkPermission(el, binding) {
const { value } = binding
const isOk = await hasPermission(value) // 这里会把权限code和所有权限码进行匹配,如果包含则返回true
if (!isOk) {
el.parentNode && el.parentNode.removeChild(el)
}
}
export default {
inserted(el, binding) {
checkPermission(el, binding)
},
update(el, binding) {
checkPermission(el, binding)
}
}
---------------------------------------------------------------------
// 路径 src/directive/index.js
import Vue from 'vue';
import permission from './permission';
// 权限控制
Vue.directive('permission', permission);