RBAC模块分析:菜单-权限/角色-权限/用户-角色

19 阅读5分钟

微服务模块的请求链路分析与权限设计

在这篇博客中,我们将探讨一个微服务模块中用户、角色、菜单和权限之间的对应关系,并详细分析其核心请求链路。通过清晰的结构和时序图,我们将展示系统的设计逻辑和实现细节。

用户/角色/菜单/权限的对应关系

在权限设计中,我们定义了以下关系:

  • 用户和角色: 多对多关系(M:N)。一个用户可以拥有多个角色,一个角色可以被多个用户拥有。
  • 角色和权限: 多对多关系(M:N)。一个角色可以关联多个权限,一个权限可以被多个角色使用。
  • 权限和菜单: 多对一关系(M:1)。一个权限对应一个菜单,但一个菜单可以拥有多个权限。

这种设计允许灵活的权限分配,同时确保菜单与权限之间的明确映射。以下是一个简单的关系示意图:

用户 ↔ (M:N) 角色 ↔ (M:N) 权限 → (M:1) 菜单

这种结构支持复杂的权限管理需求,例如一个菜单可能需要多个权限才能访问,而这些权限可以动态分配给不同的角色。

微服务模块的请求链路分析

在这个微服务模块中,我们识别出三个核心请求链路:

  1. 菜单管理相关的请求链路
  2. 菜单权限相关的请求链路
  3. 角色管理相关的请求链路

下面我们将逐一分析这些链路的实现细节。


1. 菜单管理的请求链路

1.1 获取路由菜单
MenuController.route()
  -> MenuService.listBySysType()
    -> MenuMapper.listBySysType()
  1. 用户访问 /menu/route 接口。
  2. MenuController.route() 方法被调用。
  3. MenuService.listBySysType() 查询当前用户有权限访问的菜单列表。
  4. MenuMapper.listBySysType() 从数据库中获取菜单数据。
1.2 获取单个菜单
MenuController.getByMenuId()
  -> MenuService.getByMenuId()
    -> MenuMapper.getByMenuId()
  1. 用户访问 /menu?menuId={id} 接口。
  2. MenuController.getByMenuId() 方法被调用。
  3. MenuService.getByMenuId() 查询指定菜单详情。
  4. MenuMapper.getByMenuId() 从数据库中获取数据。
1.3 保存菜单
MenuController.save()
  -> MenuService.save()
    -> MenuMapper.save()
  1. 用户通过 /menu 接口发起 POST 请求。
  2. MenuController.save() 方法被调用。
  3. MenuService.save() 保存菜单数据。
  4. MenuMapper.save() 将数据插入数据库。
1.4 更新菜单
MenuController.update()
  -> MenuService.update()
    -> MenuMapper.update()
  1. 用户通过 /menu 接口发起 PUT 请求。
  2. MenuController.update() 方法被调用。
  3. MenuService.update() 更新菜单数据。
  4. MenuMapper.update() 将数据更新到数据库。
1.5 删除菜单
MenuController.delete()
  -> MenuService.deleteById()
    -> MenuMapper.deleteById()
  1. 用户访问 /menu?menuId={id} 接口发起 DELETE 请求。
  2. MenuController.delete() 方法被调用。
  3. MenuService.deleteById() 删除指定菜单。
  4. MenuMapper.deleteById() 从数据库中删除数据。

2. 菜单权限的请求链路

2.1 获取菜单下的权限列表
MenuPermissionController.listByMenuId()
  -> MenuPermissionService.listByMenuId()
    -> MenuPermissionMapper.listByMenuId()
  1. 用户访问 /menu_permission/list_by_menu?menuId={id} 接口。
  2. MenuPermissionController.listByMenuId() 方法被调用。
  3. MenuPermissionService.listByMenuId() 查询权限列表。
  4. MenuPermissionMapper.listByMenuId() 从数据库中获取数据。
2.2 获取单个菜单权限
MenuPermissionController.getByMenuPermissionId()
  -> MenuPermissionService.getByMenuPermissionId()
    -> MenuPermissionMapper.getByMenuPermissionId()
  1. 用户访问 /menu_permission?menuPermissionId={id} 接口。
  2. MenuPermissionController.getByMenuPermissionId() 方法被调用。
  3. MenuPermissionService.getByMenuPermissionId() 查询权限详情。
  4. MenuPermissionMapper.getByMenuPermissionId() 从数据库中获取数据。
2.3 保存菜单权限
MenuPermissionController.save()
  -> MenuPermissionService.save()
    -> MenuPermissionMapper.save()
  1. 用户通过 /menu_permission 接口发起 POST 请求。
  2. MenuPermissionController.save() 方法被调用。
  3. MenuPermissionService.save() 保存权限数据。
  4. MenuPermissionMapper.save() 将数据插入数据库。
2.4 更新菜单权限
MenuPermissionController.update()
  -> MenuPermissionService.update()
    -> MenuPermissionMapper.update()
  1. 用户通过 /menu_permission 接口发起 PUT 请求。
  2. MenuPermissionController.update() 方法被调用。
  3. MenuPermissionService.update() 更新权限数据。
  4. MenuPermissionMapper.update() 将数据更新到数据库。
2.5 删除菜单权限
MenuPermissionController.delete()
  -> MenuPermissionService.deleteById()
    -> MenuPermissionMapper.deleteById()
  1. 用户访问 /menu_permission?menuPermissionId={id} 接口发起 DELETE 请求。
  2. MenuPermissionController.delete() 方法被调用。
  3. MenuPermissionService.deleteById() 删除指定权限。
  4. MenuPermissionMapper.deleteById() 从数据库中删除数据。

3. 角色管理的请求链路

3.1 分页获取角色列表
RoleController.page()
  -> RoleService.page()
    -> RoleMapper.list()
  1. 用户访问 /role/page 接口。
  2. RoleController.page() 方法被调用。
  3. RoleService.page() 查询角色分页数据。
  4. RoleMapper.list() 从数据库中获取角色列表。
3.2 获取单个角色
RoleController.getByRoleId()
  -> RoleService.getByRoleId()
    -> RoleMapper.getByRoleId()
    -> RoleMenuMapper.getByRoleId()
  1. 用户访问 /role?roleId={id} 接口。
  2. RoleController.getByRoleId() 方法被调用。
  3. RoleService.getByRoleId() 查询角色详情。
  4. RoleMapper.getByRoleId() 从数据库中获取角色数据。
  5. RoleMenuMapper.getByRoleId() 获取关联的菜单和权限ID。
3.3 保存角色
RoleController.save()
  -> RoleService.save()
    -> RoleMapper.save()
    -> RoleMenuMapper.insertBatch()
  1. 用户通过 /role 接口发起 POST 请求。
  2. RoleController.save() 方法被调用。
  3. RoleService.save() 保存角色数据。
  4. RoleMapper.save() 将角色数据插入数据库。
  5. RoleMenuMapper.insertBatch() 保存角色与菜单/权限的关联。
3.4 更新角色
RoleController.update()
  -> RoleService.update()
    -> RoleMapper.update()
    -> RoleMenuMapper.deleteByRoleId()
    -> RoleMenuMapper.insertBatch()
  1. 用户通过 /role 接口发起 PUT 请求。
  2. RoleController.update() 方法被调用。
  3. RoleService.update() 更新角色数据。
  4. RoleMapper.update() 将角色数据更新到数据库。
  5. RoleMenuMapper.deleteByRoleId() 删除旧的关联关系。
  6. RoleMenuMapper.insertBatch() 保存新的关联关系。
3.5 删除角色
RoleController.delete()
  -> RoleService.deleteById()
    -> RoleMapper.deleteById()
    -> RoleMenuMapper.deleteByRoleId()
    -> UserRoleMapper.deleteByRoleId()
  1. 用户访问 /role?roleId={id} 接口发起 DELETE 请求。
  2. RoleController.delete() 方法被调用。
  3. RoleService.deleteById() 删除指定角色。
  4. RoleMapper.deleteById() 从数据库中删除角色数据。
  5. RoleMenuMapper.deleteByRoleId() 删除角色与菜单/权限的关联。
  6. UserRoleMapper.deleteByRoleId() 删除用户与角色的关联。

请求链路时序图

以下是整个模块核心请求链路的 Mermaid 时序图:

sequenceDiagram
    participant Client
    participant MenuController
    participant MenuService
    participant MenuMapper
    participant MenuPermissionController
    participant MenuPermissionService
    participant MenuPermissionMapper
    participant RoleController
    participant RoleService
    participant RoleMapper
    participant RoleMenuMapper
    participant UserRoleMapper

    Client->>MenuController: GET /menu/route
    MenuController->>MenuService: listBySysType()
    MenuService->>MenuMapper: listBySysType()
    MenuMapper-->>MenuService: 菜单列表
    MenuService-->>MenuController: 菜单列表

    Client->>MenuPermissionController: GET /menu_permission/list_by_menu
    MenuPermissionController->>MenuPermissionService: listByMenuId()
    MenuPermissionService->>MenuPermissionMapper: listByMenuId()
    MenuPermissionMapper-->>MenuPermissionService: 权限列表
    MenuPermissionService-->>MenuPermissionController: 权限列表

    Client->>RoleController: GET /role/page
    RoleController->>RoleService: page()
    RoleService->>RoleMapper: list()
    RoleMapper-->>RoleService: 角色分页列表
    RoleService-->>RoleController: 角色分页列表

    Client->>RoleController: GET /role
    RoleController->>RoleService: getByRoleId()
    RoleService->>RoleMapper: getByRoleId()
    RoleMapper-->>RoleService: 角色详情
    RoleService->>RoleMenuMapper: getByRoleId()
    RoleMenuMapper-->>RoleService: 关联菜单权限ID
    RoleService-->>RoleController: 角色详情

    Client->>RoleController: POST /role
    RoleController->>RoleService: save()
    RoleService->>RoleMapper: save()
    RoleMapper-->>RoleService: 保存角色
    RoleService->>RoleMenuMapper: insertBatch()
    RoleMenuMapper-->>RoleService: 保存角色菜单权限关系

    Client->>RoleController: PUT /role
    RoleController->>RoleService: update()
    RoleService->>RoleMapper: update()
    RoleMapper-->>RoleService: 更新角色
    RoleService->>RoleMenuMapper: deleteByRoleId()
    RoleMenuMapper-->>RoleService: 删除旧菜单权限关系
    RoleService->>RoleMenuMapper: insertBatch()
    RoleMenuMapper-->>RoleService: 保存新菜单权限关系

    Client->>RoleController: DELETE /role
    RoleController->>RoleService: deleteById()
    RoleService->>RoleMapper: deleteById()
    RoleMapper-->>RoleService: 删除角色
    RoleService->>RoleMenuMapper: deleteByRoleId()
    RoleMenuMapper-->>RoleService: 删除角色菜单权限关系
    RoleService->>UserRoleMapper: deleteByRoleId()
    UserRoleMapper-->>RoleService: 删除用户角色关系

总结

通过以上分析,我们可以看到:

  1. 职责清晰:Controller 负责请求处理,Service 实现业务逻辑,Mapper 负责数据库操作。
  2. 事务管理:在保存或更新角色等复杂操作中,Service 层通过事务控制确保数据一致性。
  3. 灵活性与可维护性:M:N 和 M:1 的关系设计支持动态权限分配,同时模块化的请求链路便于扩展和优化。

这份分析为后续的功能开发和性能优化提供了坚实的基础,同时也展示了微服务架构下权限管理的典型实现方式。