1059 lines
46 KiB
Markdown
1059 lines
46 KiB
Markdown
# 身份与权限域 - 详细设计
|
||
|
||
**文档版本**: v1.0
|
||
**生成日期**: 2026-05-18
|
||
**数据来源**: module-auth 实际代码 + REVERSE-AUTH.md
|
||
**对照需求**: 05-AUTH.md
|
||
|
||
---
|
||
|
||
## 一、功能点清单
|
||
|
||
| 功能ID | 功能名称 | 优先级 | 实现状态 | 对应需求ID |
|
||
|--------|----------|--------|----------|------------|
|
||
| AUTH-001 | 用户登录 | P0 | 已实现 | 05-AUTH-001 |
|
||
| AUTH-002 | 用户登出 | P0 | 已实现 | 05-AUTH-002 |
|
||
| AUTH-003 | 获取当前用户 | P0 | 已实现 | 05-AUTH-003 |
|
||
| AUTH-004 | Token刷新 | P0 | 已实现 | 05-AUTH-004 |
|
||
| AUTH-005 | 用户CRUD | P0 | 已实现 | 05-AUTH-010 |
|
||
| AUTH-006 | 修改密码 | P0 | 已实现 | 05-AUTH-011 |
|
||
| AUTH-007 | 分配用户角色 | P0 | 已实现 | 05-AUTH-020 |
|
||
| AUTH-008 | 用户项目关联 | P1 | 已实现 | 05-AUTH-030 |
|
||
| AUTH-009 | 企业员工管理 | P1 | 已实现 | 05-AUTH-012 |
|
||
| AUTH-010 | 角色CRUD | P0 | 已实现 | 05-AUTH-020 |
|
||
| AUTH-011 | 角色权限分配 | P0 | 已实现 | 05-AUTH-021 |
|
||
| AUTH-012 | 按项目查询角色 | P1 | 已实现 | 05-AUTH-022 |
|
||
| AUTH-013 | 权限CRUD | P0 | 已实现 | 05-AUTH-025 |
|
||
| AUTH-014 | 按类型查询权限 | P1 | 已实现 | 05-AUTH-026 |
|
||
| AUTH-015 | 菜单权限查询 | P1 | 已实现 | 05-AUTH-027 |
|
||
| AUTH-016 | 部门树管理 | P1 | 已实现 | 05-AUTH-040 |
|
||
| AUTH-017 | 部门成员查询 | P1 | 已实现 | 05-AUTH-041 |
|
||
| AUTH-018 | 项目成员管理 | P0 | 已实现 | 05-AUTH-030 |
|
||
| AUTH-019 | 登录失败锁定 | P0 | 已实现 | 05-AUTH-005 |
|
||
| AUTH-020 | 密码强度校验 | P0 | 已实现 | 05-AUTH-006 |
|
||
| AUTH-021 | 弱密码检测 | P1 | 已实现 | 05-AUTH-007 |
|
||
| AUTH-022 | 审计日志查询 | P1 | 已实现 | 05-AUTH-050 |
|
||
| AUTH-023 | 审计日志统计 | P2 | 已实现 | 05-AUTH-051 |
|
||
| AUTH-024 | 系统配置管理 | P1 | 已实现 | 05-AUTH-060 |
|
||
| AUTH-025 | 数据访问授权 | P2 | 已实现(@Deprecated) | 05-AUTH-035 |
|
||
| AUTH-026 | 住户认证流程 | P1 | 已实现 | 05-AUTH-015 |
|
||
| AUTH-027 | 住户房屋绑定 | P1 | 已实现 | 05-AUTH-016 |
|
||
| AUTH-028 | 项目员工角色分配 | P1 | 已实现 | 05-AUTH-031 |
|
||
|
||
---
|
||
|
||
## 二、数据结构设计
|
||
|
||
### 2.1 实体定义
|
||
|
||
#### 2.1.1 User(用户)
|
||
|
||
**表名**: `auth_user`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 用户唯一标识符 |
|
||
| username | VARCHAR(50) | NOT NULL, UNIQUE, 正则`^[a-zA-Z0-9_]+$`, 3-50位 | 登录用户名 |
|
||
| password | VARCHAR(255) | NOT NULL, @JsonIgnore | BCrypt加密密码 |
|
||
| salt | VARCHAR | @JsonIgnore | 密码盐值(BCrypt模式下冗余) |
|
||
| realName | VARCHAR(50) | | 真实姓名 |
|
||
| phone | VARCHAR(20) | 正则`^1[3-9]\d{9}$` | 手机号码 |
|
||
| email | VARCHAR(100) | @Email | 电子邮箱 |
|
||
| avatar | VARCHAR | | 头像URL |
|
||
| status | VARCHAR(20) | NOT NULL, 默认ACTIVE, @Enumerated(STRING) | 用户状态枚举 |
|
||
| userType | VARCHAR(20) | NOT NULL | 用户类型:ENTERPRISE/PROJECT_STAFF/RESIDENT/CUSTOMER |
|
||
| deptId | UUID | | 所属部门ID |
|
||
| lastLoginTime | LocalDateTime | | 最后登录时间 |
|
||
| lastLoginIp | VARCHAR | | 最后登录IP |
|
||
| createdAt | LocalDateTime | NOT NULL, @PrePersist自动填充 | 创建时间 |
|
||
| updatedAt | LocalDateTime | NOT NULL, @PreUpdate自动填充 | 更新时间 |
|
||
| createdBy | UUID | | 创建人ID |
|
||
|
||
**索引**:
|
||
- `auth_user_username_key` → username (UNIQUE)
|
||
|
||
**关系**:
|
||
- `roles` → M2M → Role(通过 `auth_user_role` 中间表,LAZY加载)
|
||
|
||
**中间表: auth_user_role**
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| user_id | UUID | FK → auth_user, fk_auth_user_role_user | 用户ID |
|
||
| role_id | UUID | FK → auth_role, fk_auth_user_role_role | 角色ID |
|
||
|
||
---
|
||
|
||
#### 2.1.2 Role(角色)
|
||
|
||
**表名**: `auth_role`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 角色唯一标识符 |
|
||
| code | VARCHAR(50) | NOT NULL, UNIQUE, 正则`^[a-zA-Z0-9_]+$`, 2-50位 | 角色代码 |
|
||
| name | VARCHAR(50) | NOT NULL, 2-50位 | 角色名称 |
|
||
| description | VARCHAR(200) | | 角色描述 |
|
||
| type | VARCHAR(20) | NOT NULL, @Enumerated(STRING) | 角色类型枚举 |
|
||
| dataScope | VARCHAR(20) | 默认SELF, @Enumerated(STRING) | 数据范围枚举 |
|
||
| projectId | UUID | columnDefinition=uuid | 所属项目ID(NULL=系统级) |
|
||
| status | VARCHAR(20) | NOT NULL, 默认ENABLED, @Enumerated(STRING) | 角色状态枚举 |
|
||
| createdAt | LocalDateTime | NOT NULL, @PrePersist自动填充 | 创建时间 |
|
||
| updatedAt | LocalDateTime | NOT NULL, @PreUpdate自动填充 | 更新时间 |
|
||
|
||
**索引**:
|
||
- `auth_role_code_key` → code (UNIQUE)
|
||
|
||
**关系**:
|
||
- `permissions` → M2M → Permission(通过 `auth_role_permission` 中间表,LAZY加载)
|
||
|
||
**中间表: auth_role_permission**
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| role_id | UUID | FK → auth_role, fk_auth_role_permission_role | 角色ID |
|
||
| permission_id | UUID | FK → auth_permission, fk_auth_role_permission_permission | 权限ID |
|
||
|
||
---
|
||
|
||
#### 2.1.3 Permission(权限)
|
||
|
||
**表名**: `auth_permission`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 权限唯一标识符 |
|
||
| code | VARCHAR(100) | NOT NULL, UNIQUE, 正则`^[a-zA-Z0-9_:]+$`, 2-100位 | 权限代码,格式`module:resource:action` |
|
||
| name | VARCHAR(100) | NOT NULL, 2-100位 | 权限名称 |
|
||
| type | VARCHAR(20) | | 权限类型:MENU/BUTTON/API |
|
||
| resource | VARCHAR(50) | | 资源路径(API类型) |
|
||
| method | VARCHAR(50) | | HTTP方法(API类型) |
|
||
| description | VARCHAR(200) | | 权限描述 |
|
||
| parentCode | VARCHAR(50) | | 父权限代码(树形结构) |
|
||
| path | VARCHAR(200) | | 路由路径(菜单类型) |
|
||
| component | VARCHAR(200) | | 组件路径(菜单类型) |
|
||
| icon | VARCHAR(100) | | 图标名称(菜单类型) |
|
||
| sortOrder | Integer | | 排序序号 |
|
||
| visible | Boolean | NOT NULL, 默认true | 是否可见 |
|
||
| createdAt | LocalDateTime | @PrePersist自动填充 | 创建时间 |
|
||
| updatedAt | LocalDateTime | @PreUpdate自动填充 | 更新时间 |
|
||
|
||
**索引**:
|
||
- `auth_permission_code_key` → code (UNIQUE)
|
||
|
||
**关系**:
|
||
- `roles` → M2M → Role(通过 `auth_role_permission` 中间表,LAZY加载,@JsonIgnoreProperties避免循环序列化)
|
||
|
||
---
|
||
|
||
#### 2.1.4 Dept(部门)
|
||
|
||
**表名**: `dept`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 部门唯一标识符 |
|
||
| parentId | UUID | | 上级部门ID(NULL=顶级) |
|
||
| deptName | VARCHAR(100) | NOT NULL | 部门名称 |
|
||
| deptType | VARCHAR(20) | 默认"ADMIN" | 部门类型 |
|
||
| leaderId | UUID | | 部门负责人ID |
|
||
| sortOrder | Integer | | 排序序号 |
|
||
| status | VARCHAR(20) | 默认"ACTIVE" | 状态:ACTIVE/DISABLED |
|
||
| createdAt | LocalDateTime | @PrePersist自动填充 | 创建时间 |
|
||
| updatedAt | LocalDateTime | @PreUpdate自动填充 | 更新时间 |
|
||
| createdBy | UUID | column: created_by | 创建人ID |
|
||
| updatedBy | UUID | column: updated_by | 更新人ID |
|
||
|
||
**关系**:
|
||
- 自引用树形结构:parentId → Dept.id
|
||
|
||
---
|
||
|
||
#### 2.1.5 AuditLog(审计日志)
|
||
|
||
**表名**: `sys_audit_log`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 日志ID |
|
||
| userId | UUID | column: user_id | 操作用户ID |
|
||
| username | VARCHAR(64) | NOT NULL | 操作用户名 |
|
||
| operation | VARCHAR(128) | NOT NULL | 操作描述 |
|
||
| module | VARCHAR(64) | NOT NULL | 模块标识 |
|
||
| action | VARCHAR(64) | NOT NULL, @Enumerated(STRING) | 操作类型枚举 |
|
||
| targetType | VARCHAR(64) | | 目标类型 |
|
||
| targetId | VARCHAR(64) | | 目标ID |
|
||
| content | VARCHAR(2000) | | 操作内容 |
|
||
| params | LONGVARCHAR(5000) | | 请求参数 |
|
||
| result | LONGVARCHAR(5000) | | 操作结果 |
|
||
| ipAddress | VARCHAR(64) | column: ip_address | IP地址 |
|
||
| userAgent | VARCHAR(512) | | 用户代理 |
|
||
| requestUrl | VARCHAR(512) | column: request_url | 请求URL |
|
||
| requestMethod | VARCHAR(16) | column: request_method | 请求方法 |
|
||
| executionTimeMs | Integer | column: execution_time_ms | 执行耗时(ms) |
|
||
| status | VARCHAR(16) | 默认SUCCESS, @Enumerated(STRING) | 状态枚举 |
|
||
| errorMsg | VARCHAR(2000) | column: error_msg | 错误信息 |
|
||
| createdAt | LocalDateTime | NOT NULL, @CreationTimestamp, 不可更新 | 创建时间 |
|
||
| tenantId | UUID | column: tenant_id | 租户ID |
|
||
|
||
**索引**:
|
||
- `idx_audit_log_created_at` → createdAt
|
||
- `idx_audit_log_user_id` → userId
|
||
- `idx_audit_log_module` → module
|
||
- `idx_audit_log_action` → action
|
||
- `idx_al_user_createdat` → userId, createdAt DESC
|
||
|
||
---
|
||
|
||
#### 2.1.6 EnterpriseUser(企业员工)
|
||
|
||
**表名**: `enterprise_user`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| userId | UUID | PK, FK → auth_user | 用户ID(共享主键) |
|
||
| employeeNo | VARCHAR(50) | | 员工工号 |
|
||
| deptId | UUID | | 部门ID |
|
||
| position | VARCHAR(50) | | 职位 |
|
||
| entryDate | LocalDate | | 入职日期 |
|
||
| userCategory | VARCHAR(50) | | 员工类别:ENTERPRISE/MANAGEMENT |
|
||
|
||
**关系**:
|
||
- `user` → @OneToOne → User(@MapsId共享主键)
|
||
|
||
---
|
||
|
||
#### 2.1.7 ProjectStaff(项目员工)
|
||
|
||
**表名**: `project_staff`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 主键ID |
|
||
| userId | UUID | FK → auth_user, insertable=false, updatable=false | 用户ID |
|
||
| projectId | UUID | column: project_id | 所属项目ID |
|
||
| deptId | UUID | column: dept_id | 所属部门ID |
|
||
| staffType | VARCHAR(50) | | 员工类型:SECURITY/CLEANING/GARDEN/MAINTENANCE/CUSTOMER_SERVICE/GENERAL |
|
||
| shiftType | VARCHAR(20) | | 班次类型:DAY/NIGHT/ROTATION |
|
||
| leaderId | UUID | | 班组长ID |
|
||
| assignmentStatus | VARCHAR(20) | | 在岗状态:ASSIGNED/ON_LEAVE/TRANSFERRED |
|
||
| createdAt | LocalDateTime | column: created_at, 不可更新 | 创建时间 |
|
||
| updatedAt | LocalDateTime | column: updated_at | 更新时间 |
|
||
|
||
**关系**:
|
||
- `user` → @OneToOne → User(FK: fk_project_staff_user)
|
||
- `staffRoles` → @OneToMany → ProjectStaffRole(mappedBy="staff", CASCADE=ALL, orphanRemoval=true)
|
||
|
||
---
|
||
|
||
#### 2.1.8 ProjectStaffRole(项目员工角色)
|
||
|
||
**表名**: `project_staff_role`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 主键ID |
|
||
| staff_id | UUID | FK → project_staff, NOT NULL | 关联项目员工 |
|
||
| role_id | UUID | FK → auth_role, NOT NULL | 关联角色 |
|
||
| createdAt | LocalDateTime | column: created_at, @PrePersist自动填充 | 创建时间 |
|
||
|
||
**关系**:
|
||
- `staff` → @ManyToOne(LAZY) → ProjectStaff
|
||
- `role` → @ManyToOne(EAGER) → Role
|
||
|
||
---
|
||
|
||
#### 2.1.9 Resident(住户)
|
||
|
||
**表名**: `resident`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| userId | UUID | PK, FK → auth_user | 用户ID(共享主键) |
|
||
| idCard | VARCHAR(18) | @JsonIgnore | 身份证号码 |
|
||
| residentType | VARCHAR(20) | | 住户类型:OWNER/FAMILY/TENANT |
|
||
| verificationStatus | VARCHAR(20) | | 认证状态:UNVERIFIED/PENDING/VERIFIED/REJECTED |
|
||
| verifiedAt | LocalDateTime | | 认证时间 |
|
||
| verifiedBy | UUID | | 认证人ID |
|
||
| createdAt | LocalDateTime | NOT NULL, @PrePersist自动填充 | 创建时间 |
|
||
| updatedAt | LocalDateTime | NOT NULL, @PreUpdate自动填充 | 更新时间 |
|
||
| createdBy | UUID | column: created_by | 创建人ID |
|
||
| updatedBy | UUID | column: updated_by | 更新人ID |
|
||
|
||
**关系**:
|
||
- `user` → @OneToOne → User(@MapsId共享主键)
|
||
|
||
---
|
||
|
||
#### 2.1.10 Space(房屋空间)
|
||
|
||
**表名**: `space`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 空间ID |
|
||
| projectId | UUID | column: project_id | 所属项目ID |
|
||
| building | VARCHAR(50) | | 楼栋 |
|
||
| unit | VARCHAR(50) | | 单元 |
|
||
| roomNo | VARCHAR(50) | | 房号 |
|
||
| spaceType | VARCHAR(20) | | 房屋类型:RESIDENTIAL/COMMERCIAL |
|
||
| floor | Integer | | 楼层 |
|
||
| unitArea | BigDecimal | | 建筑面积(㎡) |
|
||
| status | VARCHAR(20) | | 状态 |
|
||
|
||
---
|
||
|
||
#### 2.1.11 ResidentSpace(住户-房屋关联)
|
||
|
||
**表名**: `resident_space`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 关联记录ID |
|
||
| userId | UUID | NOT NULL, column: user_id | 用户ID |
|
||
| spaceId | UUID | NOT NULL, column: space_id | 房屋ID |
|
||
| relationType | VARCHAR(20) | | 关系类型:OWNER/FAMILY/TENANT |
|
||
| bindingStatus | VARCHAR(20) | | 绑定状态:PENDING/ACTIVE/EXPIRED/CANCELLED |
|
||
| startDate | LocalDate | | 生效日期 |
|
||
| endDate | LocalDate | | 失效日期(NULL=永久) |
|
||
|
||
---
|
||
|
||
#### 2.1.12 UserProject(用户-项目关联)
|
||
|
||
**表名**: `user_project`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 关联记录ID |
|
||
| userId | UUID | NOT NULL, column: user_id | 用户ID |
|
||
| projectId | UUID | NOT NULL, column: project_id | 项目ID |
|
||
| roleInProject | VARCHAR | NOT NULL, 默认"member", column: role_in_project | 项目中角色:leader/member/viewer |
|
||
| joinedAt | LocalDateTime | NOT NULL, 默认当前时间, column: joined_at | 加入时间 |
|
||
|
||
---
|
||
|
||
#### 2.1.13 SysConfig(系统配置)
|
||
|
||
**表名**: `sys_config`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 配置项ID |
|
||
| configKey | VARCHAR(128) | NOT NULL, UNIQUE, column: config_key | 配置键 |
|
||
| configValue | VARCHAR(5000) | column: config_value | 配置值 |
|
||
| description | VARCHAR(256) | | 配置描述 |
|
||
| createdAt | LocalDateTime | NOT NULL, @CreationTimestamp, 不可更新 | 创建时间 |
|
||
| updatedAt | LocalDateTime | NOT NULL, @UpdateTimestamp | 更新时间 |
|
||
|
||
---
|
||
|
||
#### 2.1.14 DataAccess(数据访问授权)@Deprecated
|
||
|
||
**表名**: `biz_data_access`
|
||
|
||
| 字段名 | 类型 | 约束 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | UUID | PK, 自动生成 | 授权记录ID |
|
||
| dataType | VARCHAR | NOT NULL, column: data_type | 数据类型 |
|
||
| dataId | UUID | NOT NULL, column: data_id | 数据ID |
|
||
| accessType | VARCHAR | NOT NULL, column: access_type | 访问者类型 |
|
||
| accessId | UUID | NOT NULL, column: access_id | 访问者ID |
|
||
| accessLevel | VARCHAR | NOT NULL, 默认"read", column: access_level | 访问级别 |
|
||
| grantedBy | UUID | column: granted_by | 授权人ID |
|
||
| grantedAt | LocalDateTime | NOT NULL, 默认当前时间, column: granted_at | 授权时间 |
|
||
|
||
> **注意**: DataAccess 实体及对应控制器已标记 @Deprecated,后续版本将移除。
|
||
|
||
---
|
||
|
||
### 2.2 枚举定义
|
||
|
||
#### UserStatus
|
||
|
||
| 值 | 描述 |
|
||
|----|------|
|
||
| ACTIVE | 正常 |
|
||
| LOCKED | 锁定 |
|
||
| DISABLED | 禁用 |
|
||
|
||
#### RoleType
|
||
|
||
| 值 | 描述 |
|
||
|----|------|
|
||
| SYSTEM | 系统级,可访问所有项目数据 |
|
||
| PROJECT | 项目级,仅可访问指定项目数据 |
|
||
| DEPARTMENT | 部门级,仅可访问本部门数据 |
|
||
|
||
#### DataScope
|
||
|
||
| 值 | 描述 |
|
||
|----|------|
|
||
| ALL | 全部数据 |
|
||
| PROJECT | 本项目数据 |
|
||
| DEPARTMENT | 本部门数据 |
|
||
| SELF | 仅本人数据 |
|
||
|
||
#### RoleStatus
|
||
|
||
| 值 | 描述 |
|
||
|----|------|
|
||
| ENABLED | 启用 |
|
||
| DISABLED | 禁用 |
|
||
|
||
#### DeptType
|
||
|
||
| 值 | 描述 |
|
||
|----|------|
|
||
| ADMIN | 行政管理 |
|
||
| ENGINEERING | 工程部 |
|
||
| SECURITY | 安保部 |
|
||
| CS | 客服部 |
|
||
| CLEANING | 保洁部 |
|
||
|
||
#### ActionType
|
||
|
||
| 值 | 描述 |
|
||
|----|------|
|
||
| CREATE | 创建 |
|
||
| UPDATE | 修改 |
|
||
| DELETE | 删除 |
|
||
| QUERY | 查询 |
|
||
| VIEW | 查看 |
|
||
| LOGIN | 登录 |
|
||
| LOGOUT | 登出 |
|
||
| EXPORT | 导出 |
|
||
| IMPORT | 导入 |
|
||
| ASSIGN | 分配 |
|
||
| REVOKE | 撤销 |
|
||
|
||
---
|
||
|
||
### 2.3 ER关系图(Mermaid)
|
||
|
||
```mermaid
|
||
erDiagram
|
||
User ||--o{ Role : "auth_user_role M2M"
|
||
Role ||--o{ Permission : "auth_role_permission M2M"
|
||
User ||--|| EnterpriseUser : "共享主键 1:1"
|
||
User ||--|| ProjectStaff : "FK 1:1"
|
||
User ||--|| Resident : "共享主键 1:1"
|
||
ProjectStaff ||--o{ ProjectStaffRole : "1:N 级联删除"
|
||
ProjectStaffRole }o--|| Role : "N:1 EAGER"
|
||
Resident ||--o{ ResidentSpace : "1:N"
|
||
ResidentSpace }o--|| Space : "N:1"
|
||
User ||--o{ UserProject : "1:N"
|
||
UserProject }o--|| Project : "N:1"
|
||
|
||
Dept ||--o{ Dept : "自引用树形 parentId"
|
||
|
||
AuditLog {
|
||
UUID id PK
|
||
UUID userId
|
||
String username
|
||
String operation
|
||
String module
|
||
String action
|
||
String targetType
|
||
String targetId
|
||
String status
|
||
}
|
||
|
||
SysConfig {
|
||
UUID id PK
|
||
String configKey UK
|
||
String configValue
|
||
}
|
||
|
||
DataAccess {
|
||
UUID id PK
|
||
String dataType
|
||
UUID dataId
|
||
String accessType
|
||
UUID accessId
|
||
String accessLevel
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 三、API设计
|
||
|
||
### 3.1 AuthController -- 认证管理
|
||
|
||
**基础路径**: `/api/auth`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| AUTH-API-001 | POST | `/login` | 用户登录 | Body: `{username: String(3-50), password: String(8-128)}` | `{code, data: {token, userId, username, realName, roles}}` | 无(公开) | 用户名不存在; 密码错误; 账户锁定; 账户禁用; 登录失败超5次锁定10分钟 |
|
||
| AUTH-API-002 | POST | `/logout` | 用户登出 | Header: Authorization: Bearer {token} | `{code, data: null}` | 已登录 | Token无效 |
|
||
| AUTH-API-003 | GET | `/me` | 获取当前用户 | Header: Authorization: Bearer {token} | `{code, data: {username}}` | 已登录 | Token缺失; Token无效 |
|
||
| AUTH-API-004 | POST | `/refresh` | 刷新Token | Header: Authorization: Bearer {token} | `{code, data: {token}}` | 已登录 | Token缺失; Token无效; Token已过期 |
|
||
|
||
**登录响应详细格式**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"data": {
|
||
"token": "eyJhbGciOiJIUzI1NiJ9...",
|
||
"userId": "uuid",
|
||
"username": "admin",
|
||
"realName": "管理员",
|
||
"roles": ["SYSTEM_ADMIN", "PROJECT_MANAGER"]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.2 UserController -- 用户管理
|
||
|
||
**基础路径**: `/api/auth/users`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| USER-API-001 | GET | `/` | 分页查询用户列表 | page(int, 默认0), size(int, 默认10) | `{code, data: {content: [User], totalElements, totalPages, ...}}` | 已登录 | 分页参数越界 |
|
||
| USER-API-002 | GET | `/{id}` | 根据ID获取用户 | id(UUID, Path) | `{code, data: User}` | 已登录 | 用户不存在 |
|
||
| USER-API-003 | POST | `/` | 创建用户 | Body: User实体 | `{code, data: User}` | 管理员 | 用户名已存在; 字段校验失败 |
|
||
| USER-API-004 | PUT | `/{id}` | 更新用户 | id(UUID, Path), Body: User实体 | `{code, data: User}` | 管理员 | 用户不存在; 用户名冲突 |
|
||
| USER-API-005 | DELETE | `/{id}` | 删除用户 | id(UUID, Path) | `{code, data: null}` | 管理员 | 用户不存在; 用户有关联数据 |
|
||
| USER-API-006 | PUT | `/{id}/password` | 修改密码 | id(UUID, Path), Body: `{oldPassword: String(8-128), newPassword: String(8-128)}` | `{code, data: null}` | 本人或管理员 | 原密码错误; 新密码强度不足; 新密码为弱密码 |
|
||
| USER-API-007 | POST | `/{id}/roles` | 分配角色 | id(UUID, Path), Body: `[roleId1, roleId2, ...]` | `{code, data: null}` | 管理员 | 用户不存在; 角色ID不存在; 分配数量超限 |
|
||
| USER-API-008 | GET | `/{id}/projects` | 获取用户项目列表 | id(UUID, Path) | `{code, data: [UserProject]}` | 已登录 | 用户不存在 |
|
||
| USER-API-009 | POST | `/{id}/projects` | 添加用户到项目 | id(UUID, Path), Body: `{projectId: UUID, roleInProject: String}` | `{code, data: null}` | 管理员 | 用户不存在; 项目不存在; 已在该项目中 |
|
||
| USER-API-010 | DELETE | `/{id}/projects/{projectId}` | 从项目移除用户 | id(UUID, Path), projectId(UUID, Path) | `{code, data: null}` | 管理员 | 关联不存在 |
|
||
| USER-API-011 | GET | `/enterprise` | 获取企业员工列表 | 无 | `{code, data: [UserVO]}` | 已登录 | 无 |
|
||
|
||
**UserVO格式**:
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"username": "zhangsan",
|
||
"realName": "张三",
|
||
"phone": "13800138000",
|
||
"email": "zhangsan@example.com",
|
||
"avatar": "url",
|
||
"status": "ACTIVE",
|
||
"userType": "ENTERPRISE",
|
||
"deptId": "uuid"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 RoleController -- 角色管理
|
||
|
||
**基础路径**: `/api/auth/roles`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| ROLE-API-001 | GET | `/` | 分页查询角色列表 | page(int, 默认0), size(int, 默认10) | `{code, data: Page<Role>}` | 已登录 | 分页参数越界 |
|
||
| ROLE-API-002 | GET | `/{id}` | 根据ID获取角色 | id(UUID, Path) | `{code, data: Role}` | 已登录 | 角色不存在 |
|
||
| ROLE-API-003 | GET | `/project/{projectId}` | 根据项目ID查询角色 | projectId(UUID, Path) | `{code, data: [Role]}` | 已登录 | 项目不存在 |
|
||
| ROLE-API-004 | POST | `/` | 创建角色 | Body: Role实体 | `{code, data: Role}` | 管理员 | 角色代码已存在; 字段校验失败 |
|
||
| ROLE-API-005 | PUT | `/{id}` | 更新角色 | id(UUID, Path), Body: Role实体 | `{code, data: Role}` | 管理员 | 角色不存在; 角色代码冲突 |
|
||
| ROLE-API-006 | DELETE | `/{id}` | 删除角色 | id(UUID, Path) | `{code, data: null}` | 管理员 | 角色不存在; 角色已分配给用户 |
|
||
| ROLE-API-007 | POST | `/{id}/permissions` | 为角色分配权限 | id(UUID, Path), Body: `[permissionId1, permissionId2, ...]` | `{code, data: null}` | 管理员 | 角色不存在; 权限ID不存在 |
|
||
| ROLE-API-008 | GET | `/{id}/permissions` | 获取角色权限列表 | id(UUID, Path) | `{code, data: [Permission]}` | 已登录 | 角色不存在 |
|
||
| ROLE-API-009 | GET | `/{id}/users` | 获取拥有某角色的用户 | id(UUID, Path) | `{code, data: [User]}` | 已登录 | 角色不存在 |
|
||
|
||
---
|
||
|
||
### 3.4 PermissionController -- 权限管理
|
||
|
||
**基础路径**: `/api/auth/permissions`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| PERM-API-001 | GET | `/` | 分页查询权限列表 | page(int, 默认0), size(int, 默认10) | `{code, data: Page<Permission>}` | 已登录 | 分页参数越界 |
|
||
| PERM-API-002 | GET | `/{id}` | 根据ID获取权限 | id(UUID, Path) | `{code, data: Permission}` | 已登录 | 权限不存在 |
|
||
| PERM-API-003 | GET | `/type/{type}` | 根据类型查询权限 | type(String, Path): MENU/BUTTON/API | `{code, data: [Permission]}` | 已登录 | 无效类型 |
|
||
| PERM-API-004 | GET | `/menus` | 查询所有菜单权限 | 无 | `{code, data: [Permission]}` | 已登录 | 无 |
|
||
| PERM-API-005 | POST | `/` | 创建权限 | Body: Permission实体 | `{code, data: Permission}` | 管理员 | 权限代码已存在; 字段校验失败 |
|
||
| PERM-API-006 | PUT | `/{id}` | 更新权限 | id(UUID, Path), Body: Permission实体 | `{code, data: Permission}` | 管理员 | 权限不存在; 权限代码冲突 |
|
||
| PERM-API-007 | DELETE | `/{id}` | 删除权限 | id(UUID, Path) | `{code, data: null}` | 管理员 | 权限不存在; 权限已分配给角色 |
|
||
|
||
---
|
||
|
||
### 3.5 DeptController -- 部门管理
|
||
|
||
**基础路径**: `/api/auth/depts`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| DEPT-API-001 | GET | `/tree` | 获取部门树 | 无 | `{code, data: [DeptVO]}` | 已登录 | 无 |
|
||
| DEPT-API-002 | GET | `/` | 获取所有启用部门 | 无 | `{code, data: [Dept]}` | 已登录 | 无 |
|
||
| DEPT-API-003 | GET | `/{id}` | 根据ID获取部门 | id(UUID, Path) | `{code, data: Dept}` | 已登录 | 部门不存在 |
|
||
| DEPT-API-004 | POST | `/` | 创建部门 | Body: DeptDTO `{deptName, parentId, deptType, leaderId, sortOrder}` | `{code, data: Dept}` | 管理员 | 父部门不存在; 字段校验失败 |
|
||
| DEPT-API-005 | PUT | `/{id}` | 更新部门 | id(UUID, Path), Body: DeptDTO | `{code, data: Dept}` | 管理员 | 部门不存在; 形成环 |
|
||
| DEPT-API-006 | DELETE | `/{id}` | 删除部门 | id(UUID, Path) | `{code, data: null}` | 管理员 | 部门不存在; 有子部门; 部门下有用户 |
|
||
| DEPT-API-007 | GET | `/{deptId}/members` | 获取部门成员 | deptId(UUID, Path) | `{code, data: [UserVO]}` | 已登录 | 部门不存在 |
|
||
| DEPT-API-008 | GET | `/by-type/{deptType}` | 根据类型查询部门 | deptType(String, Path): ADMIN/ENGINEERING/SECURITY/CS/CLEANING | `{code, data: [Dept]}` | 已登录 | 无效类型 |
|
||
|
||
**DeptVO格式**:
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"parentId": "uuid",
|
||
"deptName": "工程部",
|
||
"deptType": "ENGINEERING",
|
||
"leaderId": "uuid",
|
||
"sortOrder": 1,
|
||
"status": "ACTIVE",
|
||
"children": [DeptVO, DeptVO, ...]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.6 ProjectMemberController -- 项目成员管理
|
||
|
||
**基础路径**: `/api/auth/projects`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| PMM-API-001 | GET | `/{projectId}/members` | 查询项目成员列表 | projectId(UUID, Path), page(int, 默认0), size(int, 默认20) | `{code, data: PageResponse<ProjectMemberVO>}` | 已登录 | 项目不存在 |
|
||
| PMM-API-002 | GET | `/{projectId}/available-members` | 获取可添加成员 | projectId(UUID, Path), search(String, 可选) | `{code, data: [UserVO]}` | 已登录 | 项目不存在 |
|
||
| PMM-API-003 | POST | `/{projectId}/members` | 添加项目成员 | projectId(UUID, Path), Body: AddProjectMemberDTO `{userId, staffType, roleIds}` | `{code, data: null}` | 项目管理员 | 用户不存在; 项目不存在; 用户已是成员 |
|
||
| PMM-API-004 | DELETE | `/{projectId}/members/{userId}` | 移除项目成员 | projectId(UUID, Path), userId(UUID, Path) | `{code, data: null}` | 项目管理员 | 成员不存在 |
|
||
|
||
**ProjectMemberVO格式**:
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"userId": "uuid",
|
||
"username": "zhangsan",
|
||
"realName": "张三",
|
||
"staffType": "SECURITY",
|
||
"shiftType": "DAY",
|
||
"assignmentStatus": "ASSIGNED",
|
||
"roles": [
|
||
{"id": "uuid", "code": "SECURITY_GUARD", "name": "保安"}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.7 DataAccessController -- 数据访问授权 @Deprecated
|
||
|
||
**基础路径**: `/api/data-access`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| DA-API-001 | POST | `/` | 授予数据访问权限 | Body: DataAccessRequest `{dataType, dataId, accessType, accessId, accessLevel}` | `{code, data: null}` | 已登录 | 未登录(401); 字段校验失败 |
|
||
| DA-API-002 | DELETE | `/{id}` | 撤销数据访问权限 | id(UUID, Path) | `{code, data: null}` | 已登录 | 记录不存在 |
|
||
| DA-API-003 | GET | `/` | 查询数据访问记录 | dataType(String), dataId(UUID) | `{code, data: [DataAccess]}` | 已登录 | 参数缺失 |
|
||
|
||
> **注意**: 此控制器所有端点已标记 @Deprecated,后续版本将移除。
|
||
|
||
---
|
||
|
||
### 3.8 AuditLogController -- 审计日志
|
||
|
||
**基础路径**: `/api/audit-logs`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| AUDIT-API-001 | GET | `/` | 分页查询审计日志 | page(int, 默认0), size(int, 默认10), module(String, 可选), action(String, 可选), username(String, 可选), startDate(DateTime, 可选), endDate(DateTime, 可选) | `{code, data: Page<AuditLog>}` | 管理员 | 查询范围超30天自动截断 |
|
||
| AUDIT-API-002 | GET | `/modules` | 获取模块列表 | 无 | `{code, data: [{value, label}]}` | 管理员 | 无 |
|
||
| AUDIT-API-003 | GET | `/actions` | 获取操作类型列表 | 无 | `{code, data: [{value, label}]}` | 管理员 | 无 |
|
||
| AUDIT-API-004 | GET | `/stats` | 获取最近30天日志统计 | 无 | `{code, data: {total, retentionDays, description}}` | 管理员 | 无 |
|
||
|
||
**模块列表固定值**: USER(用户管理), ROLE(角色管理), PERMISSION(权限管理), PROJECT(项目管理), AUTH(登录认证)
|
||
|
||
---
|
||
|
||
### 3.9 SysConfigController -- 系统配置
|
||
|
||
**基础路径**: `/api/config`
|
||
|
||
| 编号 | 方法 | 路径 | 说明 | 请求参数 | 响应格式 | 权限要求 | 例外情况 |
|
||
|------|------|------|------|----------|----------|----------|----------|
|
||
| CFG-API-001 | GET | `/` | 获取所有配置项 | 无 | `{code, data: {key1: value1, key2: value2}}` | 管理员 | 无 |
|
||
| CFG-API-002 | GET | `/{configKey}` | 根据键获取配置 | configKey(String, Path) | `{code, data: SysConfig}` | 管理员 | 配置键不存在 |
|
||
| CFG-API-003 | PUT | `/{configKey}` | 更新单个配置 | configKey(String, Path), Body: `{configValue: String(NotBlank)}` | `{code, data: SysConfig}` | 管理员 | 配置键不存在; 配置值为空 |
|
||
| CFG-API-004 | PUT | `/` | 批量更新配置 | Body: `{key1: value1, key2: value2}` | `{code, data: {key1: value1, key2: value2}}` | 管理员 | 配置键不存在 |
|
||
|
||
---
|
||
|
||
## 四、业务规则
|
||
|
||
### 4.1 RBAC权限模型(角色-权限-用户关联规则)
|
||
|
||
**模型结构**: User <--M2M--> Role <--M2M--> Permission
|
||
|
||
**双层角色分配**:
|
||
|
||
1. **用户直接角色**: 通过 `auth_user_role` 中间表关联
|
||
- 用户创建时分配
|
||
- 通过 `UserController.assignRoles` 接口分配
|
||
- 覆盖模式:新分配的角色列表完全替换旧列表
|
||
|
||
2. **项目员工角色**: 通过 `ProjectStaffRole` 关联
|
||
- 项目成员管理时分配
|
||
- 覆盖模式:先删除旧角色,再添加新角色
|
||
- 级联删除:删除 ProjectStaff 时自动删除其所有 ProjectStaffRole
|
||
|
||
**登录时角色收集规则**:
|
||
```
|
||
用户所有角色 = 用户直接角色(auth_user_role) ∪ 项目员工角色(ProjectStaffRole → Role)
|
||
```
|
||
|
||
**角色类型与数据范围对应关系**:
|
||
|
||
| 角色类型 | 说明 | 默认数据范围 | projectId |
|
||
|---------|------|-------------|-----------|
|
||
| SYSTEM | 系统级角色,跨项目 | ALL | NULL |
|
||
| PROJECT | 项目级角色,绑定特定项目 | PROJECT | 非NULL |
|
||
| DEPARTMENT | 部门级角色 | DEPARTMENT | NULL |
|
||
|
||
**角色分配约束**:
|
||
- 角色分配数量受 `BatchOperationValidator.validateAssignmentSize()` 限制
|
||
- 分配不存在的角色ID将抛出异常
|
||
- 角色状态为 DISABLED 时不应分配给用户(需业务层校验)
|
||
|
||
---
|
||
|
||
### 4.2 数据范围控制(ALL/PROJECT/DEPARTMENT/SELF的SQL过滤规则)
|
||
|
||
**四级数据范围**:
|
||
|
||
| 数据范围 | 编码 | 说明 | SQL过滤规则 |
|
||
|---------|------|------|------------|
|
||
| 全部 | ALL | 可查看所有数据 | 不做数据过滤 |
|
||
| 项目 | PROJECT | 仅可查看所属项目数据 | `WHERE project_id IN (用户可访问的项目ID列表)` |
|
||
| 部门 | DEPARTMENT | 仅可查看本部门数据 | `WHERE project_id IN (...) AND dept_id = 用户部门ID` |
|
||
| 本人 | SELF | 仅可查看本人数据 | `WHERE assigned_to = 当前用户ID OR created_by = 当前用户ID` |
|
||
|
||
**DataScopeService 核心方法**:
|
||
|
||
| 方法 | 说明 | 返回值 |
|
||
|------|------|--------|
|
||
| `canAccessAllData()` | 检查角色集中是否有ALL范围 | Boolean |
|
||
| `isSelfScopeOnly()` | 检查是否所有角色都是SELF范围 | Boolean |
|
||
| `getPermittedProjectIds()` | 获取用户可访问的项目ID列表 | List\<UUID\> |
|
||
|
||
**项目上下文传递机制**:
|
||
1. 前端请求携带 `X-Project-ID` Header
|
||
2. `ProjectContextInterceptor` 拦截器设置 ThreadLocal
|
||
3. 业务层通过 DataScopeService 过滤数据
|
||
|
||
---
|
||
|
||
### 4.3 JWT认证流程(登录→Token生成→验证→刷新→登出)
|
||
|
||
**Token生成**:
|
||
- 算法: HMAC-SHA256
|
||
- Claims: userId(subject), username, roles列表
|
||
- 过期时间: 可配置(默认86400000ms = 24小时)
|
||
- 密钥: 配置项 `jwt.secret`
|
||
|
||
**完整认证流程**:
|
||
|
||
```
|
||
1. 登录 POST /api/auth/login
|
||
├── 检查登录锁定(Redis: login:attempt:{username})
|
||
├── 查询用户(含角色, LAZY加载)
|
||
├── 验证密码(BCrypt.matches)
|
||
├── 检查用户状态(LOCKED/DISABLED → 拒绝)
|
||
├── 收集角色(直接角色 + 项目员工角色)
|
||
├── 生成JWT Token
|
||
├── 清除登录失败计数
|
||
├── 更新lastLoginTime/lastLoginIp
|
||
└── 返回 {token, userId, username, realName, roles}
|
||
|
||
2. 请求认证
|
||
├── Header: Authorization: Bearer {token}
|
||
├── JwtTokenProvider.validateToken() 验证签名和过期
|
||
└── 解析 userId / username / roles
|
||
|
||
3. Token刷新 POST /api/auth/refresh
|
||
├── 验证当前Token有效
|
||
├── 检查Token未过期
|
||
├── 生成新Token
|
||
└── 返回 {token}
|
||
|
||
4. 登出 POST /api/auth/logout
|
||
└── 客户端清除Token(服务端无状态)
|
||
```
|
||
|
||
---
|
||
|
||
### 4.4 密码策略(BCrypt/强度校验/弱密码检测/登录锁定)
|
||
|
||
**加密算法**: BCrypt(Spring Security PasswordEncoder)
|
||
|
||
**密码强度校验规则**(可配置,前缀 `password.*`):
|
||
|
||
| 规则 | 配置键 | 默认值 | 说明 |
|
||
|------|--------|--------|------|
|
||
| 最小长度 | password.minLength | 8 | 最小长度 |
|
||
| 最大长度 | password.maxLength | 20 | 最大长度 |
|
||
| 需要大写字母 | password.requireUppercase | true | 至少1个大写字母 |
|
||
| 需要小写字母 | password.requireLowercase | true | 至少1个小写字母 |
|
||
| 需要数字 | password.requireDigit | true | 至少1个数字 |
|
||
| 需要特殊字符 | password.requireSpecial | true | 至少1个特殊字符 |
|
||
|
||
**弱密码黑名单**: password, 123456, admin, qwerty, letmein, welcome, monkey, dragon
|
||
|
||
**旧密码兼容策略**:
|
||
- 检测非BCrypt格式密码(MD5/SHA-1等)
|
||
- 非BCrypt密码强制返回 `matches=false`
|
||
- 用户需通过修改密码流程重置为BCrypt格式
|
||
|
||
**登录失败锁定机制**(基于Redis):
|
||
|
||
| 参数 | 默认值 | 说明 |
|
||
|------|--------|------|
|
||
| maxAttempts | 5 | 最大失败次数 |
|
||
| lockoutDurationMinutes | 10 | 锁定时长(分钟) |
|
||
| Key格式 | `login:attempt:{username}` | Redis Key |
|
||
|
||
**锁定流程**:
|
||
1. 每次失败: increment计数,首次设置TTL
|
||
2. 达到上限(5次): isLockedOut返回true,拒绝登录
|
||
3. 登录成功: 清除计数
|
||
4. 手动解锁: unlock方法清除Key
|
||
|
||
---
|
||
|
||
### 4.5 项目成员管理(添加/移除/角色分配/在岗状态变更)
|
||
|
||
**添加项目成员流程**:
|
||
1. 接收 AddProjectMemberDTO: `{userId, staffType, roleIds}`
|
||
2. 创建/更新 ProjectStaff 记录(设定员工类型、分配状态=ASSIGNED)
|
||
3. 覆盖模式更新角色: 先删除旧 ProjectStaffRole,再添加新 ProjectStaffRole
|
||
4. 创建 UserProject 关联记录
|
||
|
||
**移除项目成员流程**:
|
||
1. 删除 ProjectStaff 记录(级联删除 ProjectStaffRole)
|
||
2. 删除 UserProject 关联记录
|
||
|
||
**在岗状态变更**:
|
||
- ASSIGNED: 已分配(正常在岗)
|
||
- ON_LEAVE: 请假(临时离岗)
|
||
- TRANSFERRED: 已调离(永久离岗)
|
||
|
||
**员工类型**:
|
||
- SECURITY(保安), CLEANING(保洁), GARDEN(绿化), MAINTENANCE(维修), CUSTOMER_SERVICE(客服), GENERAL(普通员工)
|
||
|
||
**班次类型**:
|
||
- DAY(白班), NIGHT(夜班), ROTATION(轮班)
|
||
|
||
---
|
||
|
||
### 4.6 住户认证流程(申请→审核→通过/拒绝→房屋绑定)
|
||
|
||
**认证状态流转**:
|
||
|
||
```
|
||
UNVERIFIED(未认证) → PENDING(待审核) → VERIFIED(已认证)
|
||
→ REJECTED(已拒绝) → PENDING(重新申请)
|
||
```
|
||
|
||
**认证流程**:
|
||
1. 住户注册账号,verificationStatus = UNVERIFIED
|
||
2. 住户提交认证申请(身份证、住户类型),verificationStatus = PENDING
|
||
3. 管理员审核:
|
||
- 通过: verificationStatus = VERIFIED, 记录 verifiedAt/verifiedBy
|
||
- 拒绝: verificationStatus = REJECTED
|
||
|
||
**房屋绑定流程**:
|
||
1. 住户认证通过后,创建 ResidentSpace 关联
|
||
2. 关联字段: userId, spaceId, relationType(OWNER/FAMILY/TENANT)
|
||
3. 绑定状态: PENDING(待生效) → ACTIVE(生效中) → EXPIRED(已过期) / CANCELLED(已取消)
|
||
4. 支持生效/失效日期: startDate / endDate(NULL=永久)
|
||
|
||
---
|
||
|
||
## 五、执行约束
|
||
|
||
### 5.1 用户名唯一性约束
|
||
|
||
- **数据库约束**: `auth_user.username` 列 UNIQUE
|
||
- **校验规则**: 正则 `^[a-zA-Z0-9_]+$`,长度3-50位
|
||
- **违反后果**: 创建/更新用户时抛出 DataIntegrityViolationException
|
||
- **处理方式**: 业务层先查询是否存在相同用户名,存在则抛出 BusinessException
|
||
|
||
### 5.2 角色代码唯一性约束
|
||
|
||
- **数据库约束**: `auth_role.code` 列 UNIQUE
|
||
- **校验规则**: 正则 `^[a-zA-Z0-9_]+$`,长度2-50位
|
||
- **违反后果**: 创建/更新角色时抛出 DataIntegrityViolationException
|
||
- **处理方式**: 业务层先查询是否存在相同角色代码,存在则抛出 BusinessException
|
||
|
||
### 5.3 权限代码唯一性约束
|
||
|
||
- **数据库约束**: `auth_permission.code` 列 UNIQUE
|
||
- **校验规则**: 正则 `^[a-zA-Z0-9_:]+$`,长度2-100位,格式 `module:resource:action`
|
||
- **违反后果**: 创建/更新权限时抛出 DataIntegrityViolationException
|
||
- **处理方式**: 业务层先查询是否存在相同权限代码,存在则抛出 BusinessException
|
||
|
||
### 5.4 部门树完整性约束(不能形成环)
|
||
|
||
- **约束说明**: 部门通过 parentId 自引用形成树形结构,更新 parentId 时不能形成环路
|
||
- **校验方式**: 业务层在更新 parentId 时,沿 parentId 链向上遍历,检查是否会回到当前节点
|
||
- **违反后果**: 抛出 BusinessException,提示"不能将部门设置为其子部门的下级"
|
||
- **附加约束**: 删除部门时,必须先删除或移动其所有子部门
|
||
|
||
### 5.5 密码强度约束
|
||
|
||
- **最小长度**: 8位
|
||
- **最大长度**: 20位(业务层校验)/ 128位(API层校验)
|
||
- **必须包含**: 大写字母、小写字母、数字、特殊字符各至少1个
|
||
- **弱密码检测**: 不允许使用黑名单中的密码
|
||
- **违反后果**: 修改密码时抛出 BusinessException,提示具体不满足的规则
|
||
|
||
---
|
||
|
||
## 六、权限控制
|
||
|
||
### 6.1 API端点权限矩阵
|
||
|
||
| 控制器 | 端点 | 所需角色 | 数据范围过滤 |
|
||
|--------|------|----------|-------------|
|
||
| AuthController | POST /login | 公开(无需认证) | 无 |
|
||
| AuthController | POST /logout | 已登录用户 | 无 |
|
||
| AuthController | GET /me | 已登录用户 | SELF |
|
||
| AuthController | POST /refresh | 已登录用户 | 无 |
|
||
| UserController | GET / | 管理员 | ALL/PROJECT/DEPARTMENT/SELF |
|
||
| UserController | GET /{id} | 管理员 | 同上 |
|
||
| UserController | POST / | 管理员(SYSTEM级) | 无 |
|
||
| UserController | PUT /{id} | 管理员 | 同上 |
|
||
| UserController | DELETE /{id} | 管理员(SYSTEM级) | 无 |
|
||
| UserController | PUT /{id}/password | 本人或管理员 | SELF |
|
||
| UserController | POST /{id}/roles | 管理员(SYSTEM级) | 无 |
|
||
| UserController | GET /{id}/projects | 已登录用户 | SELF |
|
||
| UserController | POST /{id}/projects | 管理员(PROJECT级) | 无 |
|
||
| UserController | DELETE /{id}/projects/{projectId} | 管理员(PROJECT级) | 无 |
|
||
| UserController | GET /enterprise | 已登录用户 | ALL/PROJECT |
|
||
| RoleController | GET / | 已登录用户 | ALL/PROJECT |
|
||
| RoleController | GET /{id} | 已登录用户 | 同上 |
|
||
| RoleController | GET /project/{projectId} | 已登录用户 | PROJECT |
|
||
| RoleController | POST / | 管理员(SYSTEM级) | 无 |
|
||
| RoleController | PUT /{id} | 管理员(SYSTEM级) | 无 |
|
||
| RoleController | DELETE /{id} | 管理员(SYSTEM级) | 无 |
|
||
| RoleController | POST /{id}/permissions | 管理员(SYSTEM级) | 无 |
|
||
| RoleController | GET /{id}/permissions | 已登录用户 | 同上 |
|
||
| RoleController | GET /{id}/users | 已登录用户 | 同上 |
|
||
| PermissionController | GET / | 已登录用户 | ALL |
|
||
| PermissionController | GET /{id} | 已登录用户 | ALL |
|
||
| PermissionController | GET /type/{type} | 已登录用户 | ALL |
|
||
| PermissionController | GET /menus | 已登录用户 | SELF(按角色过滤) |
|
||
| PermissionController | POST / | 管理员(SYSTEM级) | 无 |
|
||
| PermissionController | PUT /{id} | 管理员(SYSTEM级) | 无 |
|
||
| PermissionController | DELETE /{id} | 管理员(SYSTEM级) | 无 |
|
||
| DeptController | GET /tree | 已登录用户 | ALL |
|
||
| DeptController | GET / | 已登录用户 | ALL |
|
||
| DeptController | GET /{id} | 已登录用户 | ALL |
|
||
| DeptController | POST / | 管理员(SYSTEM级) | 无 |
|
||
| DeptController | PUT /{id} | 管理员(SYSTEM级) | 无 |
|
||
| DeptController | DELETE /{id} | 管理员(SYSTEM级) | 无 |
|
||
| DeptController | GET /{deptId}/members | 已登录用户 | DEPARTMENT |
|
||
| DeptController | GET /by-type/{deptType} | 已登录用户 | ALL |
|
||
| ProjectMemberController | GET /{projectId}/members | 项目成员 | PROJECT |
|
||
| ProjectMemberController | GET /{projectId}/available-members | 项目管理员 | PROJECT |
|
||
| ProjectMemberController | POST /{projectId}/members | 项目管理员 | PROJECT |
|
||
| ProjectMemberController | DELETE /{projectId}/members/{userId} | 项目管理员 | PROJECT |
|
||
| DataAccessController | POST / | 已登录用户(@Deprecated) | 无 |
|
||
| DataAccessController | DELETE /{id} | 已登录用户(@Deprecated) | 无 |
|
||
| DataAccessController | GET / | 已登录用户(@Deprecated) | 无 |
|
||
| AuditLogController | GET / | 管理员(SYSTEM级) | ALL |
|
||
| AuditLogController | GET /modules | 管理员(SYSTEM级) | 无 |
|
||
| AuditLogController | GET /actions | 管理员(SYSTEM级) | 无 |
|
||
| AuditLogController | GET /stats | 管理员(SYSTEM级) | ALL |
|
||
| SysConfigController | GET / | 管理员(SYSTEM级) | ALL |
|
||
| SysConfigController | GET /{configKey} | 管理员(SYSTEM级) | ALL |
|
||
| SysConfigController | PUT /{configKey} | 管理员(SYSTEM级) | 无 |
|
||
| SysConfigController | PUT / | 管理员(SYSTEM级) | 无 |
|
||
|
||
### 6.2 数据范围过滤规则
|
||
|
||
| 操作类型 | ALL范围 | PROJECT范围 | DEPARTMENT范围 | SELF范围 |
|
||
|---------|---------|------------|---------------|---------|
|
||
| 查询用户列表 | 全部用户 | 本项目成员 | 本部门用户 | 仅本人 |
|
||
| 查询角色列表 | 全部角色 | 本项目角色 | - | - |
|
||
| 查询审计日志 | 全部日志 | 本项目日志 | 本部门日志 | 本人操作日志 |
|
||
| 查询部门成员 | 全部 | 本项目部门成员 | 本部门成员 | - |
|
||
|
||
---
|
||
|
||
## 七、例外情况处理
|
||
|
||
### 7.1 用户相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| 用户名已存在 | 409 | "用户名{username}已存在" | 创建/更新前查询,存在则拒绝 |
|
||
| 用户不存在 | 404 | "用户不存在" | findById返回空时抛出 |
|
||
| 密码错误 | 401 | "用户名或密码错误" | BCrypt.matches返回false |
|
||
| 账户锁定 | 423 | "账户已锁定,请{minutes}分钟后重试" | 检查Redis锁定状态 |
|
||
| 账户禁用 | 403 | "账户已被禁用" | 检查UserStatus.DISABLED |
|
||
| 原密码错误 | 400 | "原密码不正确" | 修改密码时验证 |
|
||
| 新密码强度不足 | 400 | "密码必须包含大写字母、小写字母、数字和特殊字符,长度8-20位" | 密码策略校验 |
|
||
| 新密码为弱密码 | 400 | "该密码过于简单,请使用更复杂的密码" | 弱密码黑名单检测 |
|
||
| 手机号格式错误 | 400 | "手机号格式不正确" | 正则校验 |
|
||
| 邮箱格式错误 | 400 | "邮箱格式不正确" | @Email校验 |
|
||
| 删除有关联数据的用户 | 400 | "该用户存在关联数据,无法删除" | 检查UserProject/ProjectStaff等关联 |
|
||
|
||
### 7.2 角色相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| 角色代码已存在 | 409 | "角色代码{code}已存在" | 创建/更新前查询 |
|
||
| 角色不存在 | 404 | "角色不存在" | findById返回空时抛出 |
|
||
| 删除已分配的角色 | 400 | "该角色已分配给用户,无法删除" | 检查auth_user_role关联 |
|
||
| 角色代码格式错误 | 400 | "角色代码只能包含字母、数字和下划线" | 正则校验 |
|
||
|
||
### 7.3 权限相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| 权限代码已存在 | 409 | "权限代码{code}已存在" | 创建/更新前查询 |
|
||
| 权限不存在 | 404 | "权限不存在" | findById返回空时抛出 |
|
||
| 删除已分配的权限 | 400 | "该权限已分配给角色,无法删除" | 检查auth_role_permission关联 |
|
||
| 权限代码格式错误 | 400 | "权限代码只能包含字母、数字、冒号和下划线" | 正则校验 |
|
||
|
||
### 7.4 部门相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| 部门不存在 | 404 | "部门不存在" | getById返回空时返回error |
|
||
| 有子部门不能删除 | 400 | "该部门存在子部门,无法删除" | 检查子部门数量 |
|
||
| 部门下有用户不能删除 | 400 | "该部门下存在用户,无法删除" | 检查部门成员 |
|
||
| 部门树形成环 | 400 | "不能将部门设置为其子部门的下级" | 遍历parentId链检查 |
|
||
| 父部门不存在 | 400 | "上级部门不存在" | 创建/更新时校验parentId |
|
||
|
||
### 7.5 认证相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| Token缺失 | 401 | "未授权" | Authorization Header为空 |
|
||
| Token无效 | 401 | "Token无效" | JWT签名验证失败 |
|
||
| Token已过期 | 401 | "Token已过期" | JWT过期时间检查 |
|
||
| 登录失败超限 | 423 | "登录失败次数过多,账户已锁定{minutes}分钟" | Redis计数检查 |
|
||
| 用户名不存在 | 401 | "用户名或密码错误" | 不暴露具体原因 |
|
||
|
||
### 7.6 项目成员相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| 用户已是项目成员 | 409 | "该用户已是项目成员" | 检查ProjectStaff存在性 |
|
||
| 项目成员不存在 | 404 | "项目成员不存在" | 删除时校验 |
|
||
| 角色ID不存在 | 400 | "角色ID{id}不存在" | 分配角色时校验 |
|
||
|
||
### 7.7 系统配置相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| 配置键不存在 | 404 | "配置项{key}不存在" | 查询时校验 |
|
||
| 配置值为空 | 400 | "配置值不能为空" | @NotBlank校验 |
|
||
|
||
### 7.8 审计日志相关例外
|
||
|
||
| 例外场景 | 错误码 | 错误信息 | 处理方式 |
|
||
|---------|--------|---------|---------|
|
||
| 查询范围超30天 | 200(自动截断) | 无(自动截断起始时间) | 强制限制查询窗口 |
|
||
| 分页参数过大 | 200(自动修正) | 无(使用getSafeSize修正) | PaginationValidator校验 |
|