跳到主要内容

权限管理API

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向权限管理API,覆盖以下能力:

  • 权限查询接口:用户权限获取、角色权限查询
  • 角色管理接口:角色创建、更新、删除、查询
  • 权限数据结构与角色权限映射关系
  • 权限继承机制与数据权限范围
  • 权限验证流程、角色分配示例与权限缓存策略

目标是帮助开发者快速理解并正确使用权限与角色相关接口,同时掌握底层实现原理与最佳实践。

项目结构

权限模块由“API接口层”“业务控制器层”“服务实现层”“数据对象层”组成,遵循分层与职责分离原则:

  • API接口层:通过Feign声明远程RPC接口,供内部模块或网关调用
  • 控制器层:暴露REST接口,进行鉴权与参数校验
  • 服务实现层:封装权限与角色的核心逻辑,包括缓存、事务与数据权限处理
  • 数据对象层:角色、用户-角色、角色-菜单等实体定义

Mermaid Diagram Code:

graph TB
subgraph "API接口层"
PA["PermissionApi.java"]
RA["RoleApi.java"]
end
subgraph "业务控制器层"
PC["PermissionController.java"]
RC["RoleController.java"]
end
subgraph "服务实现层"
PS["PermissionServiceImpl.java"]
RS["RoleServiceImpl.java"]
end
subgraph "数据对象层"
RDO["RoleDO.java"]
URDO["UserRoleDO.java"]
RMDO["RoleMenuDO.java"]
end
PA --> PS
RA --> RS
PC --> PS
PC --> RS
RC --> RS
PS --> RDO
PS --> URDO
PS --> RMDO
RS --> RDO

图表来源

章节来源

核心组件

  • 权限API接口:提供用户-角色、角色-菜单、权限判断、数据权限查询等RPC接口
  • 角色API接口:提供角色合法性校验RPC接口
  • 权限控制器:提供REST接口,支持角色菜单分配、数据权限分配、用户角色分配与查询
  • 角色控制器:提供REST接口,支持角色的增删改查、分页、导出、简易列表
  • 权限服务实现:负责权限判断、角色-菜单/用户-角色映射、数据权限计算、缓存维护
  • 角色服务实现:负责角色生命周期管理、数据范围更新、角色校验与缓存

章节来源

架构总览

权限与角色相关请求在控制器层完成鉴权与参数校验后,进入服务层执行业务逻辑;服务层通过MyBatis访问数据库,同时利用Redis缓存提升查询性能;RPC接口通过Feign跨模块调用。

Mermaid Diagram Code:

sequenceDiagram
participant C as "客户端"
participant Ctrl as "PermissionController"
participant S as "PermissionServiceImpl"
participant RS as "RoleServiceImpl"
participant DB as "数据库"
participant Cache as "Redis缓存"
C->>Ctrl : "POST /system/permission/assign-user-role"
Ctrl->>Ctrl : "@PreAuthorize 校验权限"
Ctrl->>S : "assignUserRole(userId, roleIds)"
S->>Cache : "清除用户角色缓存"
S->>DB : "插入/删除用户-角色关联"
DB-->>S : "返回结果"
S-->>Ctrl : "成功"
Ctrl-->>C : "返回成功"

图表来源

详细组件分析

权限查询接口

  • 用户权限获取
    • RPC接口:根据用户ID获取其角色ID集合
    • 控制器:提供REST接口,返回用户拥有的角色编号列表
  • 角色权限查询
    • RPC接口:根据角色ID集合获取拥有这些角色的用户ID集合
    • 控制器:提供REST接口,返回角色拥有的菜单ID集合
  • 权限判断
    • RPC接口:判断用户是否拥有任一权限标识
    • 控制器:提供REST接口,返回用户拥有的角色列表
  • 数据权限
    • RPC接口:获取登录用户的部门数据权限
    • 控制器:提供REST接口,支持角色数据权限分配

章节来源

角色管理接口

  • 创建角色:校验唯一性与类型,插入数据库并记录日志
  • 更新角色:校验可更新性与唯一性,更新数据库并记录日志
  • 删除角色:校验可删除性,标记删除并清理相关关联
  • 查询角色:按ID、分页、状态、简易列表查询
  • 导出角色:导出Excel

章节来源

权限数据结构与映射关系

  • 角色表:包含角色ID、名称、编码、排序、状态、类型、备注、数据范围及指定部门集合
  • 用户-角色关联表:用户ID与角色ID的多对多映射
  • 角色-菜单关联表:角色ID与菜单ID的多对多映射

Mermaid Diagram Code:

erDiagram
ROLE_DO {
bigint id PK
string name
string code
int sort
int status
int type
string remark
int data_scope
set data_scope_dept_ids
}
USER_ROLE_DO {
bigint id PK
bigint user_id
bigint role_id
}
ROLE_MENU_DO {
bigint id PK
bigint role_id
bigint menu_id
}
ROLE_DO ||--o{ USER_ROLE_DO : "拥有"
ROLE_DO ||--o{ ROLE_MENU_DO : "授予"

图表来源

权限继承机制

  • 超级管理员角色:当用户拥有超级管理员角色时,权限判断直接返回“拥有权限”
  • 角色启用状态:仅启用状态的角色参与权限计算
  • 菜单-权限映射:权限标识通过菜单表中的权限字段进行映射,未找到对应菜单则视为无权限

Mermaid Diagram Code:

flowchart TD
Start(["开始"]) --> CheckEmpty["权限数组是否为空?"]
CheckEmpty --> |是| ReturnTrue["返回拥有权限"]
CheckEmpty --> |否| GetRoles["获取用户启用角色"]
GetRoles --> RolesEmpty{"角色为空?"}
RolesEmpty --> |是| ReturnFalse["返回无权限"]
RolesEmpty --> |否| LoopPerms["遍历权限标识"]
LoopPerms --> FindMenu["根据权限获取菜单ID集合"]
FindMenu --> MenuEmpty{"菜单为空?"}
MenuEmpty --> |是| NoPerm["无权限"]
MenuEmpty --> |否| CheckRoleMenu["检查角色是否拥有任一菜单"]
CheckRoleMenu --> HasAny{"角色与菜单交集非空?"}
HasAny --> |是| ReturnTrue
HasAny --> |否| NextPerm["下一个权限"]
NextPerm --> LoopPerms
NoPerm --> SuperAdmin["是否包含超级管理员角色?"]
SuperAdmin --> |是| ReturnTrue
SuperAdmin --> |否| ReturnFalse

图表来源

数据权限范围

  • ALL:可查看所有数据
  • DEPT_ONLY:仅本人所在部门
  • DEPT_AND_CHILD:所在部门及其子部门
  • DEPT_CUSTOM:自定义部门集合(含自身部门)
  • SELF:仅本人

Mermaid Diagram Code:

flowchart TD
S(["开始"]) --> GetRoles["获取用户启用角色"]
GetRoles --> RolesEmpty{"角色为空?"}
RolesEmpty --> |是| SelfOnly["仅本人(self=true)"]
RolesEmpty --> |否| Merge["合并各角色数据范围"]
Merge --> ScopeALL{"包含全部(all=true)?"}
ScopeALL --> |是| All["返回全部"]
ScopeALL --> |否| ScopeCustom{"包含自定义(dept_custom)?"}
ScopeCustom --> |是| AddUserDept["加入用户所在部门"]
AddUserDept --> ScopeOnly{"仅本部门(dept_only)?"}
ScopeOnly --> |是| DeptOnly["加入用户所在部门"]
ScopeOnly --> |否| ScopeChild{"包含子部门(dept_and_child)?"}
ScopeChild --> |是| ChildDept["加入用户所在部门及子部门"]
ScopeChild --> |否| SelfCheck{"包含self?"}
SelfCheck --> |是| SelfOnly
SelfCheck --> |否| End(["结束"])

图表来源

权限验证流程

  • 控制器层使用Spring Security注解进行权限校验
  • 服务层在执行角色-菜单、用户-角色变更时,清理相关Redis缓存以保证一致性
  • 超级管理员角色在权限判断中具有最高优先级

章节来源

角色分配示例

  • 分配用户角色
    • 请求:POST /system/permission/assign-user-role
    • 参数:userId、roleIds[]
    • 流程:计算新增与删除的角色,批量插入或删除用户-角色关联
  • 分配角色菜单
    • 请求:POST /system/permission/assign-role-menu
    • 参数:roleId、menuIds[]
    • 流程:清理菜单-角色缓存与权限-菜单缓存,计算差集并批量更新
  • 分配角色数据权限
    • 请求:POST /system/permission/assign-role-data-scope
    • 参数:roleId、dataScope、dataScopeDeptIds[]
    • 流程:更新角色的数据范围与指定部门集合

章节来源

权限缓存策略

  • 用户-角色缓存:用户角色ID集合缓存,变更时按用户维度失效
  • 菜单-角色缓存:菜单对应角色ID集合缓存,变更时按菜单维度失效
  • 权限-菜单缓存:权限标识对应菜单ID集合缓存,变更时按权限维度失效
  • 角色对象缓存:角色对象缓存,按角色ID维度失效

章节来源

依赖分析

  • 控制器依赖服务:PermissionController与RoleController分别依赖PermissionServiceImpl与RoleServiceImpl
  • 服务依赖DAO:PermissionServiceImpl与RoleServiceImpl依赖对应的Mapper与DO
  • 缓存依赖:服务层通过RedisKeyConstants进行缓存键管理
  • 枚举依赖:角色类型、数据范围等枚举影响业务逻辑

Mermaid Diagram Code:

classDiagram
class PermissionController
class RoleController
class PermissionServiceImpl
class RoleServiceImpl
class RoleDO
class UserRoleDO
class RoleMenuDO
PermissionController --> PermissionServiceImpl : "依赖"
RoleController --> RoleServiceImpl : "依赖"
PermissionServiceImpl --> RoleDO : "使用"
PermissionServiceImpl --> UserRoleDO : "使用"
PermissionServiceImpl --> RoleMenuDO : "使用"
RoleServiceImpl --> RoleDO : "使用"

图表来源

性能考量

  • 缓存命中率:通过Redis缓存用户-角色、菜单-角色、权限-菜单,降低数据库压力
  • 批量操作:新增/删除用户-角色、角色-菜单时采用批量插入/删除,减少IO次数
  • 惰性求值:用户部门ID通过Guava Suppliers惰性获取,避免不必要的DB查询
  • 事务一致性:多数据源场景使用分布式事务注解,确保跨表更新一致性

故障排查指南

  • 角色不存在或禁用:角色校验失败会抛出异常,需确认角色ID与状态
  • 权限不足:检查用户是否拥有对应权限标识或是否为超级管理员
  • 缓存不一致:角色或菜单变更后需清理相关缓存键,避免脏读
  • 数据权限异常:核对角色数据范围配置与指定部门集合

章节来源

结论

本权限模块通过清晰的分层设计与完善的缓存策略,提供了高效稳定的权限与角色管理能力。权限判断遵循“启用角色+超级管理员优先”的规则,数据权限支持多种范围模型,满足复杂业务场景需求。建议在生产环境中重点关注缓存一致性与异常处理,确保权限系统的稳定与安全。

附录

  • 角色类型枚举:内置角色与自定义角色区分
  • 角色数据范围枚举:ALL、DEPT_ONLY、DEPT_AND_CHILD、DEPT_CUSTOM、SELF

章节来源

用户文档
AI 助手
Agent 列表
请选择一个 Agent 开始对话
AI 问答