You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
350 lines
19 KiB
350 lines
19 KiB
|
1 month ago
|
# 角色管理模块
|
||
|
|
|
||
|
|
<cite>
|
||
|
|
**本文引用的文件**
|
||
|
|
- [RoleController.java](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java)
|
||
|
|
- [ISysRoleService.java](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java)
|
||
|
|
- [SysRoleServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java)
|
||
|
|
- [SysRole.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java)
|
||
|
|
- [SysRoleMenu.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRoleMenu.java)
|
||
|
|
- [SysUserRole.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserRole.java)
|
||
|
|
- [RoleDetailVO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java)
|
||
|
|
- [SysRoleMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysRoleMapper.java)
|
||
|
|
- [SysRoleMenuMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysRoleMenuMapper.java)
|
||
|
|
- [SysUserRoleMapper.java](file://crm-auth/src/main/java/com/crm/auth/mapper/SysUserRoleMapper.java)
|
||
|
|
- [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java)
|
||
|
|
- [DataInitializer.java](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java)
|
||
|
|
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
|
||
|
|
- [0012-role-management-architecture.md](file://docs/adr/0012-role-management-architecture.md)
|
||
|
|
</cite>
|
||
|
|
|
||
|
|
## 更新摘要
|
||
|
|
**所做更改**
|
||
|
|
- 更新了核心组件分析,详细描述了完整的RBAC角色管理系统实现
|
||
|
|
- 新增了详细的API端点说明和权限控制机制
|
||
|
|
- 完善了数据模型分析,重点突出SysRole.builtin字段的作用
|
||
|
|
- 增强了服务层业务逻辑分析,包含祖先补全机制和事务保护
|
||
|
|
- 更新了数据初始化器的幂等性实现细节
|
||
|
|
- 完善了故障排查指南和性能考虑部分
|
||
|
|
|
||
|
|
## 目录
|
||
|
|
1. [简介](#简介)
|
||
|
|
2. [项目结构](#项目结构)
|
||
|
|
3. [核心组件](#核心组件)
|
||
|
|
4. [架构总览](#架构总览)
|
||
|
|
5. [详细组件分析](#详细组件分析)
|
||
|
|
6. [依赖关系分析](#依赖关系分析)
|
||
|
|
7. [性能考虑](#性能考虑)
|
||
|
|
8. [故障排查指南](#故障排查指南)
|
||
|
|
9. [结论](#结论)
|
||
|
|
10. [附录](#附录)
|
||
|
|
|
||
|
|
## 简介
|
||
|
|
本模块为 CRM 后端的完整 RBAC(基于角色的访问控制)角色管理系统,提供角色的分页查询、新增/编辑、详情(含授权资源集合)、权限分配(祖先补全+全量替换)与删除(级联清理关联表)。系统遵循 ADR-0012 的架构决策:独立控制器、细粒度 hasAuthority 权限控制、内置角色保护、祖先节点补全、幂等数据初始化。
|
||
|
|
|
||
|
|
该实现包含了完整的角色管理功能,支持管理员通过前端界面进行角色的创建、配置和管理,同时确保系统内置角色的安全性和完整性。
|
||
|
|
|
||
|
|
## 项目结构
|
||
|
|
角色管理模块位于 crm-auth 子模块中,采用标准的 Controller → Service → Mapper 分层架构设计,实体与 DTO 分别放置在 domain/entity 与 domain/dto 包中,常量与配置分别位于 constant 与 config 包。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TB
|
||
|
|
subgraph "认证模块(crm-auth)"
|
||
|
|
RC["RoleController<br/>/api/roles/*"]
|
||
|
|
Svc["ISysRoleService / SysRoleServiceImpl"]
|
||
|
|
Mappers["SysRoleMapper / SysRoleMenuMapper / SysUserRoleMapper"]
|
||
|
|
Entities["SysRole / SysRoleMenu / SysUserRole"]
|
||
|
|
VO["RoleDetailVO"]
|
||
|
|
Cfg["DataInitializer"]
|
||
|
|
Const["AuthConstants"]
|
||
|
|
end
|
||
|
|
subgraph "基础模块(crm-base)"
|
||
|
|
Base["BaseEntity"]
|
||
|
|
end
|
||
|
|
RC --> Svc
|
||
|
|
Svc --> Mappers
|
||
|
|
Svc --> Entities
|
||
|
|
RC --> VO
|
||
|
|
Cfg --> Entities
|
||
|
|
Cfg --> Mappers
|
||
|
|
Svc --> Const
|
||
|
|
Entities --> Base
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [RoleController.java:1-98](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L1-L98)
|
||
|
|
- [ISysRoleService.java:1-43](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java#L1-L43)
|
||
|
|
- [SysRoleServiceImpl.java:1-137](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L1-L137)
|
||
|
|
- [SysRole.java:1-41](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java#L1-L41)
|
||
|
|
- [SysRoleMenu.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRoleMenu.java#L1-L31)
|
||
|
|
- [SysUserRole.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserRole.java#L1-L31)
|
||
|
|
- [RoleDetailVO.java:1-61](file://crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java#L1-L61)
|
||
|
|
- [SysRoleMapper.java:1-10](file://crm-auth/src/main/java/com/crm/auth/mapper/SysRoleMapper.java#L1-L10)
|
||
|
|
- [SysRoleMenuMapper.java:1-10](file://crm-auth/src/main/java/com/crm/auth/mapper/SysRoleMenuMapper.java#L1-L10)
|
||
|
|
- [SysUserRoleMapper.java:1-10](file://crm-auth/src/main/java/com/crm/auth/mapper/SysUserRoleMapper.java#L1-L10)
|
||
|
|
- [DataInitializer.java:1-159](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java#L1-L159)
|
||
|
|
- [BaseEntity.java:1-79](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java#L1-L79)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [RoleController.java:1-98](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L1-L98)
|
||
|
|
- [0012-role-management-architecture.md:1-69](file://docs/adr/0012-role-management-architecture.md#L1-L69)
|
||
|
|
|
||
|
|
## 核心组件
|
||
|
|
- **控制器 RoleController**:暴露 /api/roles/* 端点,统一使用 POST + 动作后缀的表单风格接口,并通过 @PreAuthorize 进行细粒度权限校验。
|
||
|
|
- **服务层 ISysRoleService / SysRoleServiceImpl**:封装角色保存、详情查询、权限分配(祖先补全+全量替换)、删除(级联清理)等核心业务逻辑,包含参数校验与事务保护。
|
||
|
|
- **数据模型 SysRole / SysRoleMenu / SysUserRole**:角色主表与角色-菜单、用户-角色关联表,继承 BaseEntity 获得通用审计字段与逻辑删除能力。
|
||
|
|
- **视图对象 RoleDetailVO**:角色详情输出,包含基本信息与已补全祖先的完整 resourceIds。
|
||
|
|
- **数据初始化 DataInitializer**:幂等创建内置角色、系统管理菜单、角色管理按钮权限点,并将全部资源分配给管理员角色。
|
||
|
|
- **常量 AuthConstants**:集中定义错误码与认证相关常量。
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [RoleController.java:1-98](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L1-L98)
|
||
|
|
- [ISysRoleService.java:1-43](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java#L1-L43)
|
||
|
|
- [SysRoleServiceImpl.java:1-137](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L1-L137)
|
||
|
|
- [SysRole.java:1-41](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java#L1-L41)
|
||
|
|
- [SysRoleMenu.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRoleMenu.java#L1-L31)
|
||
|
|
- [SysUserRole.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserRole.java#L1-L31)
|
||
|
|
- [RoleDetailVO.java:1-61](file://crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java#L1-L61)
|
||
|
|
- [DataInitializer.java:1-159](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java#L1-L159)
|
||
|
|
- [AuthConstants.java:1-64](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java#L1-L64)
|
||
|
|
|
||
|
|
## 架构总览
|
||
|
|
角色管理模块以 REST 控制器为入口,通过服务层完成业务规则与数据一致性保障,持久化层基于 MyBatis-Plus 的 Mapper 访问数据库。权限控制采用 Spring Security 的 hasAuthority,权限码由数据初始化器注入到 sys_menu 的 button 节点并绑定至 ADMIN 角色。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant FE as "前端"
|
||
|
|
participant RC as "RoleController"
|
||
|
|
participant SVC as "SysRoleServiceImpl"
|
||
|
|
participant MENU as "ISysMenuService"
|
||
|
|
participant RM as "SysRoleMenuMapper"
|
||
|
|
participant UR as "SysUserRoleMapper"
|
||
|
|
participant DB as "数据库"
|
||
|
|
FE->>RC : POST /api/roles/saveOrUpdate
|
||
|
|
RC->>SVC : saveRole(role)
|
||
|
|
SVC->>DB : 校验roleCode唯一性/内置保护/dataScope范围
|
||
|
|
SVC-->>RC : 返回保存结果
|
||
|
|
FE->>RC : POST /api/roles/assign-resources
|
||
|
|
RC->>SVC : assignResources(roleId, resourceIds)
|
||
|
|
SVC->>MENU : getAncestorIds(resourceIds)
|
||
|
|
MENU-->>SVC : 补全后的ID集合
|
||
|
|
SVC->>RM : 先删后插(全量替换sys_role_menu)
|
||
|
|
SVC-->>RC : 成功
|
||
|
|
FE->>RC : GET /api/roles/detail?roleId=...
|
||
|
|
RC->>SVC : getRoleDetail(roleId)
|
||
|
|
SVC->>RM : 查询sys_role_menu得到resourceIds
|
||
|
|
SVC-->>RC : 返回RoleDetailVO
|
||
|
|
FE->>RC : POST /api/roles/delete?id=...
|
||
|
|
RC->>SVC : deleteRoleCascade(roleId)
|
||
|
|
SVC->>RM : 清理sys_role_menu
|
||
|
|
SVC->>UR : 清理sys_user_role
|
||
|
|
SVC->>DB : 删除角色
|
||
|
|
SVC-->>RC : 成功
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [RoleController.java:1-98](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L1-L98)
|
||
|
|
- [SysRoleServiceImpl.java:1-137](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L1-L137)
|
||
|
|
- [ISysRoleService.java:1-43](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java#L1-L43)
|
||
|
|
|
||
|
|
## 详细组件分析
|
||
|
|
|
||
|
|
### 控制器 RoleController
|
||
|
|
- **端点设计**:
|
||
|
|
- POST /api/roles/page:分页查询,支持 keyword 模糊匹配角色名称。
|
||
|
|
- POST /api/roles/saveOrUpdate:新增或编辑角色,接收 roleName、roleCode、dataScope、sort、remark 等表单字段。
|
||
|
|
- GET /api/roles/detail:获取角色详情及已授权 resourceIds。
|
||
|
|
- POST /api/roles/assign-resources:分配权限资源,接受逗号分隔的 ID 字符串。
|
||
|
|
- POST /api/roles/delete:删除角色并级联清理关联。
|
||
|
|
- **权限控制**:每个端点使用 @PreAuthorize("hasAuthority('crm:role:...')") 进行细粒度鉴权。
|
||
|
|
- **输入处理**:对 resourceIds 做空值与分割过滤,避免脏数据进入服务层。
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [RoleController.java:1-98](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L1-L98)
|
||
|
|
|
||
|
|
### 服务层 ISysRoleService / SysRoleServiceImpl
|
||
|
|
- **saveRole**:
|
||
|
|
- 非空校验:roleName、roleCode 必填。
|
||
|
|
- dataScope 范围校验:1-4。
|
||
|
|
- 内置角色保护:新建时禁止设置 builtin=true;编辑内置角色禁止修改 roleCode。
|
||
|
|
- 唯一性校验:roleCode 全局唯一(排除自身)。
|
||
|
|
- **getRoleDetail**:
|
||
|
|
- 查询角色基本信息并映射为 RoleDetailVO。
|
||
|
|
- 从 sys_role_menu 读取已存储的完整 resourceIds(已含祖先)。
|
||
|
|
- **assignResources**:
|
||
|
|
- 调用 ISysMenuService.getAncestorIds 将叶子节点补全为祖先集合。
|
||
|
|
- 先删除该角色的所有角色-菜单关联,再批量插入补全后的集合,保证全量替换与原子性(@Transactional)。
|
||
|
|
- **deleteRoleCascade**:
|
||
|
|
- 内置角色保护:builtin=true 拒绝删除。
|
||
|
|
- 级联清理:先清理 sys_role_menu,再清理 sys_user_role,最后删除角色。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart TD
|
||
|
|
Start(["开始"]) --> Validate["参数校验<br/>非空/范围/唯一性/内置保护"]
|
||
|
|
Validate --> Valid{"校验通过?"}
|
||
|
|
Valid -- 否 --> ThrowErr["抛出业务异常"]
|
||
|
|
Valid -- 是 --> SaveOrUpdate["保存或更新角色"]
|
||
|
|
SaveOrUpdate --> End(["结束"])
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [SysRoleServiceImpl.java:36-79](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L36-L79)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [ISysRoleService.java:1-43](file://crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java#L1-L43)
|
||
|
|
- [SysRoleServiceImpl.java:1-137](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L1-L137)
|
||
|
|
|
||
|
|
### 数据模型与映射
|
||
|
|
- **SysRole**:角色主实体,继承 BaseEntity,包含 roleName、roleCode、dataScope、sort、remark、builtin 等字段。其中 builtin 字段用于标识内置角色,防止被意外删除或修改编码。
|
||
|
|
- **SysRoleMenu**:角色-菜单关联表,唯一约束 (role_id, menu_id)。
|
||
|
|
- **SysUserRole**:用户-角色关联表,唯一约束 (user_id, role_id)。
|
||
|
|
- **RoleDetailVO**:角色详情输出,包含 resourceIds(已补全祖先的完整授权集合)。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
classDiagram
|
||
|
|
class BaseEntity {
|
||
|
|
+Long id
|
||
|
|
+String creatorId
|
||
|
|
+LocalDateTime createTime
|
||
|
|
+String updaterId
|
||
|
|
+LocalDateTime updateTime
|
||
|
|
+Boolean deleted
|
||
|
|
}
|
||
|
|
class SysRole {
|
||
|
|
+String roleName
|
||
|
|
+String roleCode
|
||
|
|
+Integer dataScope
|
||
|
|
+Integer sort
|
||
|
|
+String remark
|
||
|
|
+Boolean builtin
|
||
|
|
}
|
||
|
|
class SysRoleMenu {
|
||
|
|
+Long id
|
||
|
|
+Long roleId
|
||
|
|
+Long menuId
|
||
|
|
}
|
||
|
|
class SysUserRole {
|
||
|
|
+Long id
|
||
|
|
+Long userId
|
||
|
|
+Long roleId
|
||
|
|
}
|
||
|
|
class RoleDetailVO {
|
||
|
|
+Long id
|
||
|
|
+String roleName
|
||
|
|
+String roleCode
|
||
|
|
+Integer dataScope
|
||
|
|
+Integer sort
|
||
|
|
+String remark
|
||
|
|
+Boolean builtin
|
||
|
|
+Long[] resourceIds
|
||
|
|
}
|
||
|
|
SysRole --|> BaseEntity : "继承"
|
||
|
|
SysRoleMenu --> SysRole : "关联"
|
||
|
|
SysUserRole --> SysRole : "关联"
|
||
|
|
RoleDetailVO ..> SysRole : "映射"
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [BaseEntity.java:1-79](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java#L1-L79)
|
||
|
|
- [SysRole.java:1-41](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java#L1-L41)
|
||
|
|
- [SysRoleMenu.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRoleMenu.java#L1-L31)
|
||
|
|
- [SysUserRole.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserRole.java#L1-L31)
|
||
|
|
- [RoleDetailVO.java:1-61](file://crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java#L1-L61)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [SysRole.java:1-41](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java#L1-L41)
|
||
|
|
- [SysRoleMenu.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRoleMenu.java#L1-L31)
|
||
|
|
- [SysUserRole.java:1-31](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserRole.java#L1-L31)
|
||
|
|
- [RoleDetailVO.java:1-61](file://crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java#L1-L61)
|
||
|
|
- [BaseEntity.java:1-79](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java#L1-L79)
|
||
|
|
|
||
|
|
### 数据初始化 DataInitializer
|
||
|
|
- **幂等初始化**:每次启动逐项检查,只补缺项。
|
||
|
|
- **内置角色**:确保 ROLE_ADMIN 存在且 builtin=true。
|
||
|
|
- **菜单树**:创建"系统管理"一级目录与"角色管理/菜单管理/部门管理"二级菜单。
|
||
|
|
- **权限点**:为角色管理创建 5 个 button 权限点(list/detail/save/delete/assign),并绑定 API URL。
|
||
|
|
- **资源绑定**:将管理员角色与上述菜单及权限点建立绑定关系。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart TD
|
||
|
|
InitStart(["启动初始化"]) --> CheckAdmin["检查ADMIN角色是否存在"]
|
||
|
|
CheckAdmin --> EnsureAdmin["不存在则创建并标记builtin=true"]
|
||
|
|
EnsureAdmin --> CreateMenus["创建系统管理菜单树"]
|
||
|
|
CreateMenus --> CreateButtons["创建角色管理button权限点"]
|
||
|
|
CreateButtons --> BindRoles["绑定ADMIN角色与菜单/权限点"]
|
||
|
|
BindRoles --> InitEnd(["初始化完成"])
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [DataInitializer.java:1-159](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java#L1-L159)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [DataInitializer.java:1-159](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java#L1-L159)
|
||
|
|
|
||
|
|
## 依赖关系分析
|
||
|
|
- 控制器依赖服务层,服务层依赖 Mapper 与菜单服务(用于祖先补全)。
|
||
|
|
- 实体均继承 BaseEntity,复用通用审计与逻辑删除能力。
|
||
|
|
- 权限码通过 DataInitializer 注入 sys_menu,并由 Spring Security 在请求阶段进行 hasAuthority 校验。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph LR
|
||
|
|
RC["RoleController"] --> SVC["SysRoleServiceImpl"]
|
||
|
|
SVC --> RM["SysRoleMenuMapper"]
|
||
|
|
SVC --> UR["SysUserRoleMapper"]
|
||
|
|
SVC --> MENU["ISysMenuService"]
|
||
|
|
SVC --> CONST["AuthConstants"]
|
||
|
|
ENT["SysRole/SysRoleMenu/SysUserRole"] --> BASE["BaseEntity"]
|
||
|
|
```
|
||
|
|
|
||
|
|
**图表来源**
|
||
|
|
- [RoleController.java:1-98](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L1-L98)
|
||
|
|
- [SysRoleServiceImpl.java:1-137](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L1-L137)
|
||
|
|
- [BaseEntity.java:1-79](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java#L1-L79)
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [RoleController.java:1-98](file://crm-auth/src/main/java/com/crm/auth/controller/RoleController.java#L1-L98)
|
||
|
|
- [SysRoleServiceImpl.java:1-137](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L1-L137)
|
||
|
|
- [BaseEntity.java:1-79](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java#L1-L79)
|
||
|
|
|
||
|
|
## 性能考虑
|
||
|
|
- **祖先补全**:建议 ISysMenuService.getAncestorIds 实现为批量查全表构建 ID→parentId 映射,内存遍历补全,避免逐节点查库。
|
||
|
|
- **全量替换策略**:assignResources 先删后插,适合角色权限变更频率不高但一次性写入量较大的场景;若变更频繁可考虑增量对比减少写放大。
|
||
|
|
- **分页查询**:page 接口使用 MyBatis-Plus 分页插件,注意 keyword 模糊匹配可能影响索引命中,必要时增加合适索引。
|
||
|
|
- **事务边界**:assignResources 与 deleteRoleCascade 使用 @Transactional 保证多表操作的原子性,避免部分失败导致数据不一致。
|
||
|
|
- **内置角色保护**:builtin 字段的引入避免了敏感角色的误操作,提升了系统安全性。
|
||
|
|
|
||
|
|
## 故障排查指南
|
||
|
|
- **常见错误码(AuthConstants)**:
|
||
|
|
- CODE_ROLE_INVALID:角色参数非法(如编码为空、dataScope 越界)。
|
||
|
|
- CODE_ROLE_CODE_DUPLICATE:角色编码重复。
|
||
|
|
- CODE_BUILTIN_ROLE_PROTECTED:内置角色保护(禁止删除或改编码)。
|
||
|
|
- **排查步骤**:
|
||
|
|
- 保存失败:检查 roleName、roleCode 是否非空,dataScope 是否在 1-4,roleCode 是否重复。
|
||
|
|
- 权限分配无效:确认前端传入的 resourceIds 是否为叶子节点,后端会补全祖先;检查 ISysMenuService.getAncestorIds 是否正确实现。
|
||
|
|
- 删除失败:确认目标角色是否为内置角色(builtin=true),内置角色不允许删除。
|
||
|
|
- 权限不足:确认当前用户是否持有对应权限码(如 crm:role:save),可通过 DataInitializer 检查权限点是否已创建并绑定。
|
||
|
|
- 内置角色问题:检查 SysRole.builtin 字段是否正确设置,确保系统内置角色的完整性。
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [AuthConstants.java:1-64](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java#L1-L64)
|
||
|
|
- [SysRoleServiceImpl.java:36-135](file://crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java#L36-L135)
|
||
|
|
- [DataInitializer.java:76-95](file://crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java#L76-L95)
|
||
|
|
|
||
|
|
## 结论
|
||
|
|
角色管理模块以清晰的层次结构与严格的业务校验为核心,结合祖先补全、事务保护与幂等初始化,提供了稳定可靠的 RBAC 角色管理能力。通过细粒度 hasAuthority 权限控制与内置角色保护,既满足安全合规要求,也为后续渐进式迁移树立了模式。
|
||
|
|
|
||
|
|
该实现完整覆盖了 RBAC 系统的核心功能,包括角色的生命周期管理、权限分配、数据完整性保护等关键特性,为企业级应用提供了坚实的基础。
|
||
|
|
|
||
|
|
## 附录
|
||
|
|
- **ADR-0012 要点回顾**:
|
||
|
|
- 独立控制器与路径 /api/roles/*。
|
||
|
|
- 分步保存:基本信息与权限分配分离。
|
||
|
|
- 术语统一:resourceIds。
|
||
|
|
- 祖先补全:放在 ISysMenuService。
|
||
|
|
- 权限控制:纯 hasAuthority,权限码由数据初始化器种子化。
|
||
|
|
- 内置角色保护:SysRole.builtin。
|
||
|
|
- 删除级联:sys_role_menu + sys_user_role。
|
||
|
|
- 数据初始化幂等化。
|
||
|
|
|
||
|
|
**章节来源**
|
||
|
|
- [0012-role-management-architecture.md:1-69](file://docs/adr/0012-role-management-architecture.md#L1-L69)
|