谷粒学院权限管理模块

=====================================================================

1.数据库表


这里系统权限控制采用的访问控制模型是 RBAC 模型

RBAC模型

RBAC 即基于角色的权限访问控制(Role-Based Access Control)。这是一种通过角色关联权限,角色同时又关联用户的授权的方式。

简单地说:一个用户可以拥有若干角色,每一个角色又可以被分配若干权限,这样就构造成“用户-角色-权限” 的授权模型。在这种模型中,用户与角色、角色与权限之间构成了多对多的关系,如下图:

RBAC

在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。

  • 菜单表acl_permission

image-20211224190642029

  • 角色表acl_role

image-20211224190701116

  • 用户表acl_user

image-20211224190713944

  • 角色—菜单表acl_role_permission

image-20211224190732158

  • 用户—角色表acl_user_role

image-20211224190744172

几个表之间的关系:

image-20211218161418810

2.菜单相关操作


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集合进行封装,具体分为这几步:

  1. 创建list集合,用于数据最终封装

  2. 把所有菜单list集合遍历,得到顶层菜单 pid=0菜单,设置level=1

  3. 根据顶层菜单,向里面进行查询子菜单,封装到最终返回结果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;

}

递归查找当前菜单的所有子菜单,具体分这几步:

  1. 因为向一层菜单里面放二层菜单,二层里面还要放三层,所以先把把子菜单集合初始化

  2. 遍历所有菜单list集合,进行判断比较,比较当前菜单pid和传过来的父菜单id值是否相同,相同就是该父菜单的子菜单

  3. 设置当前菜单level为父菜单level+1

  4. 设置子菜单,子菜单依然需要递归查询子菜单是否也有子菜单

/**

  • 递归查找当前菜单的所有子菜单

  • @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,分为这几步:

  1. 根据id查询下一层子菜单

  2. 循环变量子菜单list,将id放入idList

  3. 递归求子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获取菜单集合,具体分为这几步:

  1. 查询所有Perssion,并按id排序得到permissionList

  2. 根据roleId查询在acl_role_permission表里查询所有RolePerssion得到rolePermissionList

  3. 用stream将rolePermissionList所有对应的permissionId提取出来得到permissionIdList

  4. 遍历permissionList,如果对象的id是目标集合permissionIdList里的id,则设置select为true

  5. 把所有的菜单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.角色相关操作


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)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 11
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值