=====================================================================
这里系统权限控制采用的访问控制模型是 RBAC 模型
RBAC模型:
RBAC 即基于角色的权限访问控制(Role-Based Access Control)。这是一种通过角色关联权限,角色同时又关联用户的授权的方式。
简单地说:一个用户可以拥有若干角色,每一个角色又可以被分配若干权限,这样就构造成“用户-角色-权限” 的授权模型。在这种模型中,用户与角色、角色与权限之间构成了多对多的关系,如下图:
在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。
- 菜单表
acl_permission
- 角色表
acl_role
- 用户表
acl_user
- 角色—菜单表
acl_role_permission
- 用户—角色表
acl_user_role
几个表之间的关系:
2.1 递归查询全部菜单
controller
:
/**
-
递归获取全部菜单 √
-
@return R
*/
@GetMapping
public R indexAllPermission() {
List list = permissionService.queryAllMenuGuli();
return R.ok().data(“children”,list);
}
service
:
/**
-
递归查询所有菜单
-
@return
*/
@Override
public List queryAllMenuGuli() {
//1.查询菜单表所有数据
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
//按id从大到小排序
queryWrapper.orderByDesc(Permission::getId);
List permissionList = baseMapper.selectList(queryWrapper);
//2.把查询所有的菜单按照要求封装
List resultList = bulidPermission(permissionList);
return resultList;
}
把返回所有菜单list集合进行封装,具体分为这几步:
-
创建list集合,用于数据最终封装
-
把所有菜单list集合遍历,得到顶层菜单
pid=0
菜单,设置level=1
-
根据顶层菜单,向里面进行查询子菜单,封装到最终返回结果
finalNode
里面
/**
-
把返回所有菜单list集合进行封装的方法
-
@param permissionList
-
@return
*/
public static List bulidPermission(List permissionList) {
//1.创建list集合,用于数据最终封装
List finalNode = new ArrayList<>();
//2.把所有菜单list集合遍历,得到顶层菜单 pid=0菜单,设置level是1
for (Permission permission : permissionList) {
//得到顶层菜单 pid=0菜单
if (“0”.equals(permission.getPid())) {
//设置顶层菜单的level是1
permission.setLevel(1);
//3.根据顶层菜单,向里面进行查询子菜单,封装到finalNode里面
finalNode.add(selectChildren(permission, permissionList));
}
}
return finalNode;
}
递归查找当前菜单的所有子菜单,具体分这几步:
-
因为向一层菜单里面放二层菜单,二层里面还要放三层,所以先把把子菜单集合初始化
-
遍历所有菜单list集合,进行判断比较,比较当前菜单pid和传过来的父菜单id值是否相同,相同就是该父菜单的子菜单
-
设置当前菜单level为父菜单level+1
-
设置子菜单,子菜单依然需要递归查询子菜单是否也有子菜单
/**
-
递归查找当前菜单的所有子菜单
-
@param permissionNode 需要查找子菜单的当前菜单
-
@param permissionList 所有菜单的集合
-
@return
*/
private static Permission selectChildren(Permission permissionNode, List permissionList) {
//因为向一层菜单里面放二层菜单,二层里面还要放三层,把对象初始化
permissionNode.setChildren(new ArrayList());
//遍历所有菜单list集合,进行判断比较,比较id和pid值是否相同,是不是当前菜单的子菜单
for (Permission permission : permissionList) {
//当前菜单的pid=上级菜单id
if (permission.getPid().equals(permissionNode.getId())) {
int level = permissionNode.getLevel() + 1;
//设置当前菜单level为父菜单level+1
permission.setLevel(level);
//设置子菜单,子菜单依然需要递归查询子菜单是否也有子菜单
permissionNode.getChildren().add(selectChildren(permission, permissionList));
}
}
return permissionNode;
}
2.2 递归删除菜单
controller
:
/**
-
递归删除菜单 √
-
@param id
-
@return
*/
@DeleteMapping(“remove/{id}”)
public R remove(@PathVariable String id) {
permissionService.removeChildByIdGuli(id);
return R.ok();
}
service
:
/**
-
递归删除菜单
-
@param id 菜单id
*/
@Override
public void removeChildByIdGuli(String id) {
//1.创建list集合,用于封装所有删除菜单id值
List idList = new ArrayList<>();
//2.加入所有子菜单的id
this.selectPermissionChildById(id, idList);
//3.加入自己的id
idList.add(id);
//4.批量根据id删除菜单
baseMapper.deleteBatchIds(idList);
}
根据当前菜单id,查询其所有的子菜单的id并放入idList,分为这几步:
-
根据id查询下一层子菜单
-
循环变量子菜单list,将id放入idList
-
递归求子id的子id,也放入idList,以此类推
/**
-
根据当前菜单id,查询菜单里面子菜单id,封装到list集合
-
@param id 当前菜单id
-
@param idList 最终封装要删除的id集合
*/
private void selectPermissionChildById(String id, List idList) {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
//1.查询菜单里面子菜单id
queryWrapper.eq(Permission::getPid, id);
//2.只需要id
queryWrapper.select(Permission::getId);
List childIdList = baseMapper.selectList(queryWrapper);
//3.遍历子id集合,加入idList,然后递归遍历子菜单的子菜单
childIdList.stream().forEach(item -> {
idList.add(item.getId());
selectPermissionChildById(item.getId(), idList);
});
}
2.3 给角色分配权限
controller
:
根据角色id和菜单id集合,一个角色分配多个菜单(权限):
/**
-
给角色分配权限 √
-
@param roleId 角色id
-
@param permissionId 分配的菜单id集合
-
@return
*/
@PostMapping(“/doAssign”)
public R doAssign(String roleId,String[] permissionId) {
permissionService.saveRolePermissionRealtionShipGuli(roleId,permissionId);
return R.ok();
}
service
:
/**
-
角色分配菜单
-
@param roleId 角色id
-
@param permissionIds 菜单id集合
*/
@Override
public void saveRolePermissionRealtionShipGuli(String roleId, String[] permissionIds) {
//1.创建list集合,用于封装添加数据
List permissionList = new ArrayList<>();
for (String permissionId : permissionIds) {
if (StringUtils.isEmpty(permissionId)) continue;
RolePermission rolePermission = new RolePermission();
rolePermission.setPermissionId(permissionId);
rolePermission.setRoleId(roleId);
permissionList.add(rolePermission);
}
//2.批量保存到acl_role_permission表
rolePermissionService.saveBatch(permissionList);
}
2.4 根据角色获取菜单
controller
:
根据角色id获取对应的拥有的菜单集合:
/**
-
根据角色获取菜单
-
@param roleId
-
@return
*/
@GetMapping(“toAssign/{roleId}”)
public R toAssign(@PathVariable String roleId) {
List list = permissionService.selectAllMenu(roleId);
return R.ok().data(“children”, list);
}
service
:
根据角色id获取菜单集合,具体分为这几步:
-
查询所有Perssion,并按id排序得到permissionList
-
根据roleId查询在acl_role_permission表里查询所有RolePerssion得到rolePermissionList
-
用stream将rolePermissionList所有对应的permissionId提取出来得到permissionIdList
-
遍历permissionList,如果对象的id是目标集合permissionIdList里的id,则设置select为true
-
把所有的菜单list集合permissionList进行树状封装,递归封装,最终返回
/**
-
根据角色获取菜单
-
@param roleId 角色id
-
@return
*/
@Override
public List selectAllMenu(String roleId) {
//1.查询所有Perssion,并按id排序
List permissionList = baseMapper.selectList(new LambdaQueryWrapper().orderByDesc(Permission::getId));
//2.根据roleId查询在acl_role_permission表里查询所有RolePerssion
List rolePermissionList = rolePermissionService.list(new LambdaQueryWrapper().eq(RolePermission::getRoleId, roleId));
//3.用stream将rolePermissionList所有对应的permissionId提取出来
List permissionIdList = rolePermissionList.stream().map(e -> e.getPermissionId()).collect(Collectors.toList());
//4.遍历permissionList,如果对象的id是目标集合permissionIdList里的id,则设置select为true
permissionList.forEach(permission->{
if(permissionIdList.contains(permission.getId())){
permission.setSelect(true);
}else{
permission.setSelect(false);
}
});
//5.把所有的菜单list集合进行树状封装,递归封装
List resPermission = bulidPermission(permissionList);
return resPermission;
}
2.5 添加菜单
controller
:
直接调用mybatis-plus提供的方法:
/**
-
新增菜单 √
-
@param permission
-
@return
*/
@PostMapping(“save”)
public R save(@RequestBody Permission permission) {
permissionService.save(permission);
return R.ok();
}
2.6 修改菜单
controller
:
根据菜单id修改菜单,直接调用mybatis-plus提供的方法:
/**
-
修改菜单 √
-
@param permission
-
@return
*/
@PutMapping(“update”)
public R updateById(@RequestBody Permission permission) {
//直接根据id修改
permissionService.updateById(permission);
return R.ok();
}
3.1 获取角色分页列表
/**
-
获取角色分页列表
-
@param page 当前页
-
@param limit 每页数量
-
@param role 查询的角色,根据名字模糊查询
-
@return
*/
@GetMapping(“{page}/{limit}”)
public R index(@PathVariable Long page, @PathVariable Long limit, Role role) {
//构造page对象
Page pageParam=new Page<>(page,limit);
//构造查询,如果有名字查询则进行like模糊查询
LambdaQueryWrapper queryWrapper=new LambdaQueryWrapper<>();
if(StringUtils.isNotBlank(role.getRoleName())){
queryWrapper.like(Role::getRoleName,role.getRoleName());
}
//进行带条件的分页查询
roleService.page(pageParam,queryWrapper);
//返回最终的数据集合和总条数
return R.ok().data(“items”,pageParam.getRecords()).data(“total”,pageParam.getTotal());
}
3.2 其他操作
根据id获取角色:
/**
-
根据id获取角色
-
@param id 角色id
-
@return
*/
@GetMapping(“get/{id}”)
public R get(@PathVariable String id) {
Role role = roleService.getById(id);
return R.ok().data(“item”, role);
}
新增角色:
/**
1200页Java架构面试专题及答案
小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞
百度、字节、美团等大厂常见面试题
QueryWrapper<>();
if(StringUtils.isNotBlank(role.getRoleName())){
queryWrapper.like(Role::getRoleName,role.getRoleName());
}
//进行带条件的分页查询
roleService.page(pageParam,queryWrapper);
//返回最终的数据集合和总条数
return R.ok().data(“items”,pageParam.getRecords()).data(“total”,pageParam.getTotal());
}
3.2 其他操作
根据id获取角色:
/**
-
根据id获取角色
-
@param id 角色id
-
@return
*/
@GetMapping(“get/{id}”)
public R get(@PathVariable String id) {
Role role = roleService.getById(id);
return R.ok().data(“item”, role);
}
新增角色:
/**
1200页Java架构面试专题及答案
小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞
[外链图片转存中…(img-RDqfmzZx-1714801768987)]
[外链图片转存中…(img-aG85OteR-1714801768988)]
百度、字节、美团等大厂常见面试题
[外链图片转存中…(img-OxO7pJM3-1714801768988)]