# 身份与权限域 - 详细设计 **文档版本**: 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-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}` | 已登录 | 分页参数越界 | | 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}` | 已登录 | 项目不存在 | | 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}` | 管理员 | 查询范围超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\ | **项目上下文传递机制**: 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校验 |