开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情
前言
现在完成了基本的角色和权限结构。但为了让它们二者之间有“关系”,还得让它们在角色菜单表中通过role_id-----menu_id来建立联系。在操作角色时,应该能有一个功能就是分配角色对应的资源(权限)。除此之外,还要能够获得角色的资源。接下来我们着重来实现这两个功能。
分配角色资源
分配角色资源主要有以下几个步骤
- 获得前端传来的要分配资源的角色id及分配的菜单数组menu_ids和按钮数组permIds
- 拿着角色id到角色菜单表去查找是否有该id的权限,若有取出转换为数组
- 然后将从表中取出的数组与前端传来的权限数组判断是否有新加的权限或者有删除的权限。若有的话。新加的权限加到角色菜单表中,删除的权限从表中删除。
接下来我们通过代码来实现,在角色模型下添加一个方法。
实现方法
model/role.js
// 更新角色资源的方法
RolesModel.updateResource = async function (role_id, menu_ids) {
const t = await sequelize.transaction();
try {
// 先找到所有角色菜单表对应角色id的拥有权限
const roles_menus = await RolesMenusModel.findAll({
where: { role_id: role_id }
});
// 将表中获得的权限id转换为数组
const old_menu_ids = roles_menus.map(function (item) {
return item.menu_id;
});
// 新加的权限加到角色菜单表中
const add_menu_ids = tools.minustArr(menu_ids, old_menu_ids);
const add_roles_menus = add_menu_ids.map(function (menu_id) {
return { role_id: role_id, menu_id: menu_id };
});
await RolesMenusModel.bulkCreate(add_roles_menus);
// 删除的权限从角色菜单表删除
const del_menu_ids = tools.minustArr(old_menu_ids, menu_ids);
if (del_menu_ids && del_menu_ids.length > 0) {
await RolesMenusModel.destroy({
where: {
role_id: role_id,
menu_id: del_menu_ids
}
});
}
t.commit();
// 返回的结果
return true;
} catch (e) {
t.rollback();
return e.message;
}
};
实现了方法之后就是添加路由,编写对应路由的回调函数。
添加路由
// 获取角色资源
router.get('/roleResource', roleHandler.getRoleResource);
// 更新角色资源
router.post('/updateRoleResource', roleHandler.updateRoleResource);
路由回调函数
// 分配角色资源路由回调函数
exports.updateRoleResource = (req, res) => {
const role_id = req.query.role_id;
const data = req.body;
const all_ids = data.menu_ids.concat(data.permIds);
RoleModel.updateResource(role_id, all_ids).then(function (resource) {
if (resource !== true) {
return res.send({
code: 1,
message: '修改失败',
data: null
});
}
return res.send({
code: 0,
message: '修改成功',
data: resource
});
});
};
获取角色资源
我们还要能够有获取角色对应资源(权限)的方法。但注意最好要将获取的权限按照目录菜单和按钮分别开来,这样能使前端渲染看得更加直观。还有就是前端vue在进行权限控制的时候按钮最好是按照权限标识例如{menu_id:1,btn:["system:user:add",...]}
这样来传递而不是按钮id,因为前端按钮的权限控制多是通过指令来完成例如v-hasPerm="system:user:add"
,若用按钮的权限标识前端会更加方便。
实现步骤主要是
- 获取前端传递来的角色id到角色权限表去查询该角色id所有的权限,并转为权限id数组
- 然后通过获取的权限id去到权限表中查询权限的详细信息(在角色权限表中只存储了权限id,需要额外的信息需要到权限表去查)
- 按照目录菜单及按钮分开转换为数组,再将按钮的id数组转换格式
实现的代码如下:
model/role.js
// 获取角色资源的方法
RolesModel.getResource = async function (role_id) {
const t = await sequelize.transaction();
try {
// 所有按钮的id
let permIds = [];
// 获取角色菜单表中此角色id的所有记录
const roleResource = await RolesMenusModel.findAll({
where: { role_id: role_id }
});
// 获得此角色id的拥有权限id
const all_menu_ids = roleResource.map((resource) => {
return resource.menu_id;
});
// 从菜单表获取此角色id拥有权限详细信息
const all_menus = await MenusModel.findAll({
where: { menu_id: all_menu_ids },
attributes: ['menu_id', 'parent_id', 'type', 'permission']
});
// 获取目录及菜单的id数组
const menu__arr = all_menus.filter((menu) => menu.type === 'M' || menu.type === 'C');
const menu_ids = menu__arr.map((menu) => menu.menu_id);
// 将获取的按钮数组转化为对应的格式
const btn_arr = all_menus.filter((menu) => menu.type === 'B');
btn_arr.forEach((button) => {
permIds.push(button.menu_id);
});
t.commit();
return {
menu_ids,
buttons
};
} catch (e) {
t.rollback();
return false;
}
};
路由回调函数
exports.getRoleResource = (req, res) => {
const role_id = req.query.role_id;
RoleModel.getResource(role_id).then(function (resource) {
if (!resource) {
return res.send({
code: 1,
message: '获取角色权限失败',
data: null
});
}
return res.send({
code: 0,
message: '获取角色权限成功',
data: resource
});
});
};
测试
- 分配角色资源
- 获取角色资源