# RMDC 用户认证模块详细设计说明书 (DDS)

**产品名称**: RMDC 用户认证模块 (rmdc-user-auth)  
**版本**: v2.0  
**编制日期**: 2026-01-27

---

## 1. 概述

### 1.1 模块定位
`rmdc-user-auth` 提供 RMDC 统一的用户认证、账户生命周期管理与权限服务，支持 RSA 加密登录、JWT 鉴权、密码过期策略，以及通过工单驱动的用户注册/管理审批流程。

### 1.2 核心职责
1. **身份认证**：RSA-OAEP 密码加密 + bcrypt 校验，颁发 4h 有效的 JWT。
2. **账号管理**：用户 CRUD、密码修改、个人资料更新，支持密码过期、首次登录强制改密与状态控制（active/locked/disabled）。
3. **审批工作流集成**：用户注册/管理通过 `rmdc-work-procedure` 工单审批，遵循"谁注册谁管理"。
4. **权限服务**：
   1. Jenkins 分支层级权限（Org/Repo/Branch）权限，对外暴露权限检查接口。
   2. Project 项目权限（数据权限）权限
   3. DeliveryUpdate 微服务更新权限
5. **系统配置**：RSA 密钥对、登录策略、注册开关等配置的存取与缓存。

### 1.3 版本修订历史

| 版本 | 日期 | 修订内容 |
|:---|:---|:---|
| v1.0 | 2026-01-23 | 基于现有代码首次形成 DDS，覆盖认证、工单、权限与数据模型 |
| v2.0 | 2026-01-27 | 新增用户有效期字段、强制改密机制、用户注册/管理工单流程详细设计、模块依赖关系流程图 |

---

## 2. 系统架构

### 2.1 模块依赖关系

```mermaid
graph TB
    subgraph 核心层
        Core[rmdc-core<br/>API Gateway]
    end

    subgraph 用户与权限
        UA[rmdc-user-auth<br/>用户认证/权限]
    end

    subgraph 业务协作
        PM[rmdc-project-management<br/>项目管理]
        WP[rmdc-work-procedure<br/>工单流程]
        JB[rmdc-jenkins-branch-dac<br/>Jenkins分支权限]
    end

    subgraph 基础设施
        CMN[rmdc-common<br/>公共模块]
        Aud[rmdc-audit-log<br/>审计日志]
    end

    Core --> UA
    Core --> PM
    Core --> WP
    
    UA -->|用户注册/管理工单| WP
    UA -->|Jenkins资源查询| JB
    UA --> CMN
    UA --> Aud
    
    PM -->|用户鉴权/查询| UA
    PM -->|项目权限管理| UA
    PM -->|项目工单| WP
    
    WP -->|用户状态回调| UA
    WP -->|项目状态回调| PM
```

### 2.2 用户模块与工单模块依赖关系详图

```mermaid
graph TB
    subgraph rmdc_core["rmdc-core (入口层)"]
        INIT[模块初始化]
    end

    subgraph rmdc_user_auth["rmdc-user-auth (用户认证层)"]
        UH[UserHandler<br/>用户接口]
        UWH[UserWorkflowHandler<br/>用户工单接口]
        US[UserService<br/>用户服务]
        URS[UserRegistrationService<br/>注册工单服务]
        UMS[UserManagementService<br/>管理工单服务]
    end

    subgraph rmdc_work_procedure["rmdc-work-procedure (工单层)"]
        WH[WorkflowHandler<br/>工单接口]
        WS[WorkflowService<br/>工单服务]
        WC[WorkflowCallbacks<br/>状态回调]
    end

    INIT -->|注入用户状态回调| WS
    INIT -->|注入工单创建器| US

    UH --> US
    UWH --> URS
    UWH --> UMS

    URS -->|创建注册工单| WS
    UMS -->|创建管理工单| WS

    WC -->|审批通过: 激活用户| US
    WC -->|审批打回: 通知修改| URS
    WC -->|撤销: 删除待审批用户| US
    WC -->|管理审批通过: 执行变更| UMS
```

### 2.3 接口注入机制

采用 **接口注入（依赖注入）** 方式实现模块间回调，与项目管理模块保持一致的架构模式。

#### 2.3.1 工单模块回调用户模块的接口

```go
// UserStatusUpdater 用户状态更新接口
// 由 rmdc-core 在初始化时注入，工单模块状态变更时调用
type UserStatusUpdater interface {
    // UpdateUserStatus 更新用户状态（审批通过时激活）
    UpdateUserStatus(userID int64, status string) error
    
    // ActivateUser 激活用户（注册审批通过）
    ActivateUser(userID int64) error
    
    // DeletePendingUser 删除待审批用户（工单撤销时）
    DeletePendingUser(userID int64) error
    
    // ExecuteUserManagement 执行用户管理操作（管理审批通过）
    ExecuteUserManagement(userID int64, action string, payload map[string]interface{}) error
}
```

#### 2.3.2 用户模块调用工单模块的接口

```go
// WorkflowCreator 工单创建接口
// 由 rmdc-core 在初始化时注入，用户模块通过此接口创建工单
type WorkflowCreator interface {
    // CreateRegistrationWorkflow 创建用户注册工单
    CreateRegistrationWorkflow(ctx context.Context, req *RegistrationWorkflowRequest) (string, error)
    
    // CreateManagementWorkflow 创建用户管理工单
    CreateManagementWorkflow(ctx context.Context, req *ManagementWorkflowRequest) (string, error)
}
```

### 2.4 技术栈
- Gin (HTTP 路由)  
- GORM (ORM，依赖 `models.DatabaseConnections` 提供多库连接：User/Jenkins/Core/Workflow)  
- JWT (HS256)  
- RSA-OAEP (2048) 前端密码加密，密钥 30 天轮换  
- bcrypt (密码存储)  
- 内部模块依赖：`rmdc-work-procedure`（工单）、`rmdc-jenkins-branch-dac`（Jenkins 资源）、`rmdc-common`（日志、返回码、模型）

### 2.5 路由与中间件分层
- `/api/auth/*`：免 token，含获取 RSA 公钥、登录、注册。
- `/api/users`、`/api/user`、`/api/permissions`：需 `AuthMiddleware(jwtSecret)` 校验 JWT，部分再叠加 `RequireAdmin()`。
- 中间件：
  - `AuthMiddleware`：解析 Bearer JWT，校验签名和用户状态为 `active`，注入用户上下文。
  - `RequireAdmin`：判定角色包含 `admin` 字样（superadmin/admin）。

### 2.6 组件关系
- Handler 层：`auth_handler`、`user_handler`、`permission_handler` 注册 HTTP 路由。
- Service 层：`AuthService`、`RSAService`、`UserService`、`JenkinsPermissionService`、`SystemConfigService`、注册/管理工单服务。
- DAO 层：`UserDao`、`RSAKeypairDao`、`JenkinsPermissionDao`、`BasePermissionDao`、`SystemConfigDao`、`JenkinsDao`。
- 公共接口：`pkg/permission.PermissionChecker` 对外暴露权限检查，供其他模块调用。

---

## 3. 认证与登录设计

### 3.1 登录流程（RSA + JWT）
1. 前端调用 `GET /api/auth/rsa/public-key` 获取当前有效公钥（30 天有效，过期自动轮换）。
2. 前端用 RSA-OAEP(SHA-256, 2048) 加密密码，提交 `POST /api/auth/login`，字段 `encrypted_password`。
3. 后端 `RSAService` 解密，`AuthService` 用 bcrypt 校验 `users.password_hash`。
4. 生成 HS256 JWT，默认有效期 4h，Claims 包含用户基础信息与 `status`。
5. 返回 Token 与用户信息，并返回以下标识：
   - `must_change_password`: 首次登录或密码重置后需强制修改密码
   - `password_expire_days`: 密码剩余有效天数（7 天内提示）
   - `account_expire_days`: 账户剩余有效天数（7 天内提示）

### 3.2 密钥与密码策略
- RSA 密钥：`rsa_keypairs` 表存储 PEM，对外只暴露公钥；过期自动生成新对，异步清理过期数据。
- 密码哈希：bcrypt 默认成本；密码有效期 3 个月（注册/重置/直改都会刷新过期时间）。
- 账户状态：active/locked/disabled；JWT 校验时必须 active。
- 首次登录强制改密：新注册用户或重置密码后，`must_change_password` 标识为 true。
- 登录失败计数：字段存在，逻辑留有 TODO（未实现锁定策略）。

### 3.3 JWT 中间件行为
- 解析 Authorization: Bearer <token>，校验签名与过期。
- 校验 `claims.Status == "active"`，否则 401。
- 注入上下文键：`user_id/username/english_name/phone/group_name/role/dev_role/status`。

### 3.4 缺省/限制
- 无刷新接口；Token 过期需重新登录。
- 无服务器端注销接口（前端丢弃 Token）。

---

## 4. 用户生命周期管理

### 4.1 用户状态定义

| 状态 | 说明 | 触发条件 |
|:---|:---|:---|
| `disabled` | 待审批状态 | 用户注册后默认状态 |
| `active` | 正常激活 | 注册工单审批通过 |
| `locked` | 临时锁定 | 登录失败次数过多 / 管理员手动锁定 |

### 4.2 用户生命周期状态机

```mermaid
stateDiagram-v2
    [*] --> disabled: 用户注册
    
    disabled --> disabled: 保存草稿
    disabled --> disabled: 工单打回，等待修改
    disabled --> active: 注册工单审批通过
    disabled --> [*]: 工单撤销，删除用户
    
    active --> active: 正常使用
    active --> active: 信息更新
    active --> locked: 登录失败锁定
    active --> disabled: 管理员禁用
    active --> [*]: 管理员删除
    
    locked --> active: 解锁
    locked --> disabled: 管理员禁用
    
    note right of disabled: 用户刚注册，等待审批
    note right of active: 正常使用状态
    note right of locked: 临时锁定，可解锁
```

### 4.3 用户有效期机制

#### 4.3.1 有效期设置规则

| 用户类型 | 有效期选项 | 默认值 | 说明 |
|:---|:---|:---|:---|
| SuperAdmin 创建的用户 | 无限制 / 自定义 | 永久 | SuperAdmin 可设置任意有效期 |
| Admin 创建的用户 | 1个月/3个月/6个月/1年 | 3个月 | 必须设置有效期 |
| Normal 创建的用户 | 1个月/3个月/6个月/1年 | 3个月 | 必须设置有效期 |

#### 4.3.2 有效期字段设计

```go
// 用户表新增字段
AccountExpiresAt  *time.Time `json:"account_expires_at"`  // 账户有效期
```

#### 4.3.3 有效期检查逻辑

1. **登录时检查**：若 `account_expires_at` 不为空且已过期，拒绝登录并返回账户已过期提示
2. **接口检查**：JWT 中间件校验用户状态时，同时检查账户有效期
3. **提前提醒**：账户有效期剩余 7 天内，登录时返回提醒信息

### 4.4 强制修改密码机制

#### 4.4.1 触发条件

| 条件 | 字段标识 | 处理方式 |
|:---|:---|:---|
| 首次登录 | `must_change_password = true` | 登录成功后跳转改密页面 |
| 密码重置后 | `must_change_password = true` | 使用临时密码登录后强制改密 |
| 密码过期 | `password_expires_at` 已过期 | 拒绝登录，提示密码已过期 |

#### 4.4.2 密码过期时间线

```mermaid
flowchart TB
    A["创建用户 / 重置密码"]
    B["password_expires_at = now + 90天\nmust_change_password = true"]
    C["首次登录"]
    D["强制修改密码"]
    E["修改密码后：\npassword_expires_at = now + 90天\nmust_change_password = false"]
    F["正常使用"]
    G["第83天：提醒"]
    H["第90天：强制过期"]

    A --> B --> C --> D --> E --> F --> G --> H

```

---

## 5. 用户注册与管理权限

### 5.1 角色与注册/管理权限矩阵

| 操作者角色 | 可注册角色 | 可管理范围 | 说明 |
|:---|:---|:---|:---|
| SuperAdmin | superadmin/admin/normal/third | 所有用户 | 完全权限 |
| Admin | normal/third | 自己注册的用户 | 遵循"谁注册谁管理" |
| Normal | third | 自己注册的用户 | 仅可注册三方用户 |
| Third | - | - | 无注册和管理权限 |

### 5.2 管理操作权限矩阵

| 操作 | SuperAdmin | Admin | Normal | Third |
|:---|:---|:---|:---|:---|
| 修改用户信息 | ✅ 所有用户 | ✅ 自己注册的 | ✅ 自己注册的 | ❌ |
| 启用用户 | ✅ 所有用户 | ✅ 自己注册的 | ✅ 自己注册的 | ❌ |
| 禁用用户 | ✅ 所有用户 | ✅ 自己注册的 | ✅ 自己注册的 | ❌ |
| 删除用户 | ✅ 所有用户 | ✅ 自己注册的 | ✅ 自己注册的 | ❌ |
| 重置密码 | ✅ 所有用户 | ✅ 自己注册的 | ❌ | ❌ |
| 延长有效期 | ✅ 所有用户 | ❌ | ❌ | ❌ |

### 5.3 "谁注册谁管理"原则

1. **注册关系记录**：用户表中 `registered_by_id` 记录注册人 ID
2. **权限检查规则**：
   - SuperAdmin：可管理所有用户
   - Admin/Normal：只能管理 `registered_by_id == current_user_id` 的用户
3. **审批归属**：所有用户注册/管理工单由 SuperAdmin 审批

---

## 6. 用户注册工单流程

### 6.1 工单流程概述

```mermaid
sequenceDiagram
    participant User as 注册发起人
    participant UA as rmdc-user-auth
    participant WP as rmdc-work-procedure
    participant SA as SuperAdmin

    User->>UA: POST /api/users (创建用户)
    UA->>UA: 创建用户记录<br/>(status=disabled, 默认密码)
    UA->>WP: CreateWorkflow(user_registration)
    WP-->>UA: workflow_id
    UA-->>User: 返回成功，工单ID
    
    WP->>SA: 通知：新用户注册待审批
    
    alt 审批通过
        SA->>WP: POST /api/workflow/approve
        WP->>UA: ActivateUser(user_id)
        UA->>UA: status = active
        UA-->>WP: success
        WP->>User: 通知：用户注册已通过
    else 审批打回
        SA->>WP: POST /api/workflow/return
        WP->>User: 通知：请修改用户信息
        User->>UA: PUT /api/users/:id (修改信息)
        User->>WP: POST /api/workflow/resubmit
    else 撤销
        User->>WP: POST /api/workflow/revoke
        WP->>UA: DeletePendingUser(user_id)
        UA->>UA: DELETE users WHERE status=disabled
    end
```

### 6.2 工单状态与用户状态映射

| 工单事件 | 工单状态 | 用户状态 | 说明 |
|:---|:---|:---|:---|
| create | pending_review | disabled | 创建用户并提交审核 |
| approve | approved | active | 审核通过，激活用户 |
| return | returned | disabled (保持) | 打回修改，用户状态不变 |
| resubmit | pending_review | disabled (保持) | 重新提交审核 |
| revoke | revoked | (删除) | 撤销工单，删除待审批用户 |

### 6.3 注册工单业务载荷

```go
// RegistrationWorkflowPayload 注册工单业务载荷
type RegistrationWorkflowPayload struct {
    TargetUserID      int64     `json:"target_user_id"`      // 被注册用户ID
    TargetUsername    string    `json:"target_username"`     // 被注册用户名
    TargetRole        string    `json:"target_role"`         // 被注册用户角色
    RegisteredByID    int64     `json:"registered_by_id"`    // 注册人ID
    RegisteredByName  string    `json:"registered_by_name"`  // 注册人姓名
    AccountExpiresAt  time.Time `json:"account_expires_at"`  // 账户有效期
    RegistrationReason string   `json:"registration_reason"` // 注册原因
}
```

### 6.4 注册接口设计要点

1. **不暴露密码设置**：注册接口不接收密码参数，后端自动生成默认密码（如 `Rmdc@2026`）
2. **必须设置有效期**：非 SuperAdmin 创建用户时，必须选择有效期（1个月/3个月/6个月/1年）
3. **自动创建工单**：用户创建接口内部调用工单模块创建审批工单
4. **工单初始状态**：直接进入 `pending_review`，由 SuperAdmin 审批

---

## 7. 用户管理工单流程

### 7.1 管理操作类型

| 操作类型代码 | 操作名称 | 说明 | 需要审批 |
|:---|:---|:---|:---|
| `update` | 修改用户信息 | 修改基本信息（姓名、邮箱等） | 是 |
| `enable` | 启用用户 | 将 disabled 用户改为 active | 是 |
| `disable` | 禁用用户 | 将 active 用户改为 disabled | 是 |
| `delete` | 删除用户 | 软删除用户 | 是 |
| `reset_password` | 重置密码 | 重置为默认密码 | 是 |
| `extend_validity` | 延长有效期 | 延长账户有效期 | 是 |

### 7.2 工单流程

> **重要**：前端不允许直接调用创建工单接口，工单由用户管理接口（如 `PUT /api/users/:id`）内部自动创建。

```mermaid
sequenceDiagram
    participant Operator as 操作人
    participant UA as rmdc-user-auth
    participant WP as rmdc-work-procedure
    participant SA as SuperAdmin

    Operator->>UA: PUT /api/users/:id (修改用户信息)
    Note right of Operator: 或 POST /api/users/:id/enable|disable|delete
    UA->>UA: CheckManagementPermission
    UA->>UA: 记录原始数据快照
    UA->>WP: CreateWorkflow(user_management)
    WP-->>UA: workflow_id
    UA-->>Operator: 返回成功，工单ID

    WP->>SA: 通知：用户管理待审批
    
    alt 审批通过
        SA->>WP: POST /api/workflow/approve
        WP->>UA: ExecuteUserManagement(action, payload)
        UA->>UA: 执行对应操作(update/enable/disable/delete)
        UA-->>WP: success
        WP->>Operator: 通知：管理操作已通过
    else 审批打回
        SA->>WP: POST /api/workflow/return
        WP->>Operator: 通知：请重新提交
    end
```

### 7.3 管理工单业务载荷

```go
// ManagementWorkflowPayload 管理工单业务载荷
type ManagementWorkflowPayload struct {
    TargetUserID     int64                  `json:"target_user_id"`     // 目标用户ID
    TargetUsername   string                 `json:"target_username"`    // 目标用户名
    ActionType       string                 `json:"action_type"`        // 操作类型
    OperatorID       int64                  `json:"operator_id"`        // 操作人ID
    OperatorName     string                 `json:"operator_name"`      // 操作人姓名
    OriginalData     map[string]interface{} `json:"original_data"`      // 原始数据快照
    ModifiedData     map[string]interface{} `json:"modified_data"`      // 修改后数据
    Reason           string                 `json:"reason"`             // 操作原因
}
```

### 7.4 管理操作执行器

```go
// UserManagementExecutor 用户管理执行器
type UserManagementExecutor interface {
    // UpdateUserInfo 更新用户信息
    UpdateUserInfo(userID int64, payload map[string]interface{}) error
    
    // EnableUser 启用用户
    EnableUser(userID int64) error
    
    // DisableUser 禁用用户
    DisableUser(userID int64) error
    
    // DeleteUser 删除用户
    DeleteUser(userID int64) error
    
    // ResetPassword 重置密码
    ResetPassword(userID int64) error
    
    // ExtendValidity 延长有效期
    ExtendValidity(userID int64, newExpiresAt time.Time) error
}
```

---

## 8. 权限模型

### 8.1 统一权限架构

RMDC 系统采用**专用权限表**的设计模式，针对不同业务场景使用独立的权限表结构，以满足复杂的权限控制需求。同时定义统一的权限模块枚举，便于扩展和维护。

#### 8.1.1 权限模块枚举 (PermissionModule)

```go
// PermissionModule 权限模块枚举
type PermissionModule string

const (
    // 用户模块权限
    ModuleUserRegister     PermissionModule = "user_register"      // 用户注册
    ModuleUserManage       PermissionModule = "user_manage"        // 用户管理
    ModuleUserPermission   PermissionModule = "user_permission"    // 用户权限管理
    
    // 项目模块权限
    ModuleProjectCreate    PermissionModule = "project_create"     // 项目创建
    ModuleProjectView      PermissionModule = "project_view"       // 项目查看
    ModuleProjectEdit      PermissionModule = "project_edit"       // 项目编辑
    ModuleProjectExport    PermissionModule = "project_export"     // 项目导出
    ModuleProjectAuth      PermissionModule = "project_auth"       // 项目授权管理
    
    // Jenkins 模块权限
    ModuleJenkinsView      PermissionModule = "jenkins_view"       // Jenkins 查看
    ModuleJenkinsBuild     PermissionModule = "jenkins_build"      // Jenkins 构建
    ModuleJenkinsManage    PermissionModule = "jenkins_manage"     // Jenkins 权限管理
    
    // 微服务更新模块权限
    ModuleDeliveryView     PermissionModule = "delivery_view"      // 微服务查看
    ModuleDeliveryUpdate   PermissionModule = "delivery_update"    // 微服务更新
    
    // 工单模块权限
    ModuleWorkflowView     PermissionModule = "workflow_view"      // 工单查看
    ModuleWorkflowApprove  PermissionModule = "workflow_approve"   // 工单审批
)

// PermissionModuleInfo 模块信息
type PermissionModuleInfo struct {
    Code        PermissionModule `json:"code"`         // 模块代码
    Name        string           `json:"name"`         // 模块名称
    Description string           `json:"description"`  // 模块描述
    ACLTable    string           `json:"acl_table"`    // 关联的ACL表
}

// 模块注册表
var PermissionModules = map[PermissionModule]PermissionModuleInfo{
    ModuleJenkinsView:   {Code: ModuleJenkinsView,   Name: "Jenkins查看",     ACLTable: "jenkins_acls"},
    ModuleJenkinsBuild:  {Code: ModuleJenkinsBuild,  Name: "Jenkins构建",     ACLTable: "jenkins_acls"},
    ModuleProjectView:   {Code: ModuleProjectView,   Name: "项目查看",        ACLTable: "project_acls"},
    ModuleProjectEdit:   {Code: ModuleProjectEdit,   Name: "项目编辑",        ACLTable: "project_acls"},
    // ... 其他模块
}
```

#### 8.1.2 权限表概览

| 权限类型 | 权限表 | 权限粒度 | 说明 |
|:---|:---|:---|:---|
| **Jenkins 权限** | `jenkins_acls` | Org/Repo/Branch 层级 | 支持层级继承的 CI/CD 权限 |
| **项目权限** | `project_acls` | 项目模块级 | 项目信息访问权限 |
| **用户权限缓存** | `user_permission_caches` | 用户维度 | 用户所有权限的 L2 缓存树 |

#### 8.1.3 权限检查通用规则

```go
// 权限检查通用规则:
// 1. SuperAdmin 拥有所有权限，直接放行
// 2. 根据 PermissionModule 分流到对应的 ACL 表进行检查
// 3. 权限检查结果存入 L1 内存缓存和 L2 DB 缓存，提升性能
// 4. 权限变更时同时清除 L1 和 L2 缓存
```

### 8.2 Jenkins 层级权限 (jenkins_acls)

#### 8.2.1 层级结构

```
Organization (组织)
    └── Repository (仓库)
            └── Branch (分支)
```

#### 8.2.2 设计原则
- **层级继承**：上级权限可覆盖下级（如 Org 级权限覆盖其下所有 Repo/Branch）
- **存储最小化**：一条记录可覆盖子层级，减少数据冗余
- **权限类型**：`can_view`（查看，对应 `jenkins_view`）、`can_build`（构建，对应 `jenkins_build`）

#### 8.2.3 权限表设计 (jenkins_acls)

| 字段 | 说明 |
|:---|:---|
| `user_id` | 用户 ID |
| `organization_folder` | 组织文件夹（必填） |
| `repository_name` | 仓库名称（可空，空表示 Org 级权限） |
| `branch_name` | 分支名称（可空，空表示 Repo 级权限） |
| `permission_level` | 权限层级：org/repo/branch |
| `can_view` | 是否可查看 |
| `can_build` | 是否可构建 |
| `granted_by` | 授权人 ID |
| `granted_at` | 授权时间 |

#### 8.2.4 权限缓存机制

- **L1 内存缓存**：`permissionCache`，进程内高速缓存
- **L2 DB 缓存**：`user_permission_caches` 表，存储用户所有权限的缓存树 JSON
- **懒加载接口**：按 organizations → repositories → branches 逐级加载
- **缓存失效**：权限变更时同时清除 L1 和 L2 缓存

#### 8.2.5 权限检查逻辑

```go
// CheckHierarchicalPermission 检查层级权限
// 1. 先检查 Branch 级权限
// 2. 若无则检查 Repo 级权限
// 3. 若无则检查 Org 级权限
// 4. 支持 can_build 需求判断（build 需要 view + build 两个权限）
```

### 8.3 BusinessInfoRegistry 注册中心

权限模块需要查询业务模块信息（如项目填写人），但不应直接依赖具体业务模块。采用**统一注册机制**解决模块依赖。

```mermaid
graph TB
    subgraph rmdc_core["rmdc-core (入口层)"]
        INIT[模块初始化]
    end
    
    subgraph rmdc_user_auth["rmdc-user-auth (权限层)"]
        REG[BusinessInfoRegistry<br/>业务信息注册中心]
        PS[ProjectPermissionService]
        JS[JenkinsPermissionService]
    end
    
    subgraph business["业务模块层"]
        PM[rmdc-project-management]
        JB[rmdc-jenkins-branch-dac]
    end
    
    INIT -->|注册业务查询器| REG
    INIT -->|注入权限检查器| PM
    INIT -->|注入权限检查器| JB
    
    PS --> REG
    JS --> REG
    REG -.->|查询业务信息| PM
    REG -.->|查询Jenkins信息| JB
```

#### 8.3.1 注册接口定义

```go
// BusinessInfoQuerier 业务信息查询接口（通用基类）
type BusinessInfoQuerier interface {
    GetModuleCode() string
}

// ProjectInfoQuerier 项目信息查询接口
type ProjectInfoQuerier interface {
    BusinessInfoQuerier
    GetProjectFillerID(ctx context.Context, projectID string) (int64, error)
}

// JenkinsInfoQuerier Jenkins 信息查询接口
type JenkinsInfoQuerier interface {
    BusinessInfoQuerier
    GetOrganizations(ctx context.Context) ([]string, error)
    GetRepositories(ctx context.Context, org string) ([]string, error)
    GetBranches(ctx context.Context, org, repo string) ([]string, error)
}

// ModulePermissionChecker 权限检查器接口（通用）
type ModulePermissionChecker interface {
    CheckPermission(ctx context.Context, userID int64, userRole string,
        resourceID, resourceType, permissionType string) (bool, error)
    GetAccessibleResourceIDs(ctx context.Context, userID int64, userRole string,
        resourceType string) ([]string, error)
}
```

### 8.4 项目权限（ProjectACL）

#### 8.4.1 设计原则
- 权限粒度：**模块级**（basic_info/business_info/environment_info/middleware_info/authorization_info）
- SuperAdmin 默认拥有所有权限，无需存储 ACL 记录
- 项目填写人自动获得非授权模块的 view 权限

#### 8.4.2 模块代码与 JSONB 映射

| 模块代码 | JSONB 字段 | 说明 |
|:---|:---|:---|
| `basic_info` | `projects.basic_info` | 省份、城市、联系人等 |
| `business_info` | `projects.deploy_business` | 部署人、版本、入口等 |
| `environment_info` | `projects.deploy_env` | 主机、网络、管理方式等 |
| `middleware_info` | `projects.deploy_middleware` | MySQL/Redis/EMQX 等 |
| `authorization_info` | `project_auth_configs.*` | TOTP 授权（仅 SuperAdmin） |

#### 8.4.3 权限检查规则

```go
// CheckProjectModulePermission 规则:
// 1. SuperAdmin 拥有所有权限
// 2. authorization_info 模块仅 SuperAdmin 可访问
// 3. 项目填写人自动拥有非授权模块的 view 权限
// 4. 其他用户查询 project_acls 表
```

---

## 9. 数据模型

### 9.1 核心表概览
| 表 | 作用 | 关键字段 |
|:---|:---|:---|
| `users` | 账户信息 | username, english_username, password_hash, role, status, registered_by_id, password_expires_at, account_expires_at, must_change_password, failed_login_attempts, locked_until |
| `rsa_keypairs` | RSA 密钥对 | public_key/ private_key (PEM), expires_at |
| `jenkins_acls` | Jenkins 层级权限 | user_id, organization_folder, repository_name?, branch_name?, permission_level, can_view, can_build, granted_by |
| `project_acls` | 项目模块级权限 | user_id, project_id, module_code, can_view, can_export, granted_by |
| `user_permission_caches` | 用户权限 L2 缓存 | user_id, permission_tree (JSON), updated_at |
| `system_configs` | 系统配置 | key, value, description |

### 9.2 用户表 DDL (users)

```go
// User 用户表
type User struct {
    ID                  int64      `gorm:"primaryKey;autoIncrement" json:"id"`
    Username            string     `gorm:"uniqueIndex;not null;size:50" json:"username"`     // 中文真实姓名
    EnglishUsername     string     `gorm:"size:100" json:"english_username"`                 // 英文用户名(昵称)
    PasswordHash        string     `gorm:"not null;size:255" json:"-"`                       // 加密后的密码
    AvatarID            string     `gorm:"size:50;default:'default_1'" json:"avatar_id"`     // 头像ID
    AvatarFrameID       string     `gorm:"size:50;default:'default'" json:"avatar_frame_id"` // 头像框ID
    Gender              string     `gorm:"size:10;default:'male'" json:"gender"`             // 性别: male/female
    Email               string     `gorm:"uniqueIndex;size:100" json:"email"`                // 邮箱
    Phone               string     `gorm:"size:20" json:"phone"`                             // 手机号
    ShortNumber         string     `gorm:"size:10" json:"short_number"`                      // 短号
    WorkID              string     `gorm:"size:50" json:"work_id"`                           // 工号
    GroupName           string     `gorm:"size:100" json:"group_name"`                       // 所属小组
    Company             string     `gorm:"size:100" json:"company"`                          // 公司名称
    DevRole             string     `gorm:"size:50;default:'unknown'" json:"dev_role"`        // 开发角色
    
    // 注册关系
    RegisteredByID      int64      `json:"registered_by_id"`                                 // 注册人ID
    RegisteredByName    string     `gorm:"size:64" json:"registered_by_name"`                // 注册人姓名（冗余）
    
    // 角色与状态
    Role                string     `gorm:"not null;size:20;default:'normal'" json:"role"`    // 系统角色
    Status              string     `gorm:"not null;size:20;default:'disabled'" json:"status"` // 状态
    
    // 密码策略
    PasswordExpiresAt   *time.Time `json:"password_expires_at"`                              // 密码过期时间
    MustChangePassword  bool       `gorm:"default:true" json:"must_change_password"`         // 是否需要强制改密
    
    // 账户有效期（新增）
    AccountExpiresAt    *time.Time `json:"account_expires_at"`                               // 账户有效期
    
    // 登录锁定
    FailedLoginAttempts int        `gorm:"default:0" json:"failed_login_attempts"`
    LockedUntil         *time.Time `json:"locked_until"`
    
    // MFA
    MFASecret           string     `gorm:"size:100" json:"-"`
    
    // 审计字段
    CreatedAt           time.Time  `gorm:"autoCreateTime" json:"created_at"`
    UpdatedAt           time.Time  `gorm:"autoUpdateTime" json:"updated_at"`
    DeletedAt           *time.Time `gorm:"index" json:"deleted_at,omitempty"`
    LastLoginAt         *time.Time `json:"last_login_at"`
}
```

### 9.3 用户表新增字段说明

| 字段 | 类型 | 说明 | 默认值 |
|:---|:---|:---|:---|
| `registered_by_name` | varchar(64) | 注册人姓名（冗余存储，便于展示） | NULL |
| `must_change_password` | bool | 是否需要强制修改密码 | true |
| `account_expires_at` | datetime | 账户有效期，NULL表示永久有效 | NULL |

### 9.4 RSA 密钥表（rsa_keypairs）
- 存储 PEM 文本及过期时间；`RSAService` 负责加载、轮换、缓存与过期清理。

### 9.5 Jenkins 权限表（jenkins_acls）
- 层级列可空实现覆盖：org=不空，repo/branch 为空；repo 级：branch 空；branch 级：三列全填。
- `permission_level` 归档实际层级，便于查询。
- 详见 [8.2 Jenkins 层级权限](#82-jenkins-层级权限-jenkins_acls)。

### 9.6 项目权限表（project_acls）
- 模块级权限控制：user_id + project_id + module_code 组合唯一。
- 权限类型：can_view（查看）、can_export（导出）。
- 索引：`idx_project_acl_user`（用户维度）、`idx_project_acl_project`（项目+模块维度）。
- SuperAdmin 不存储记录，权限检查时直接放行。

---

## 10. 接口设计 (API)

### 10.1 认证
| 方法 | 路径 | 说明 | 鉴权 |
|:---|:---|:---|:---|
| GET | `/api/auth/rsa/public-key` | 获取 RSA 公钥 | 公共 |
| POST | `/api/auth/login` | RSA 加密密码登录，返回 JWT | 公共 |
| POST | `/api/auth/register` | 自助注册（创建 disabled 用户） | 公共 |

### 10.2 用户管理
| 方法 | 路径 | 说明 | 鉴权 |
|:---|:---|:---|:---|
| GET | `/api/users` | 列表，支持角色/状态/组/搜索/Scope | JWT |
| GET | `/api/users/:id` | 用户详情 + 权限 | JWT |
| POST | `/api/users` | 创建用户（自动创建注册工单） | JWT + Admin |
| PUT | `/api/users/:id` | 更新用户（仅用于保存草稿，正式修改需工单） | JWT + Admin |
| DELETE | `/api/users/:id` | 删除用户（仅SuperAdmin可直接删除） | JWT + SuperAdmin |
| PUT | `/api/user/profile` | 更新本人资料（头像/密码） | JWT |
| PUT | `/api/user/password` | 本人改密（校验旧密码） | JWT |
| PUT | `/api/user/password/force-change` | 首次登录强制改密 | JWT |

### 10.3 权限（Jenkins）
| 方法 | 路径 | 说明 | 鉴权 |
|:---|:---|:---|:---|
| GET | `/api/permissions/jenkins/my-tree/organizations` | 我的组织列表 | JWT |
| POST | `/api/permissions/jenkins/my-tree/repositories` | 我的仓库（按 org） | JWT |
| POST | `/api/permissions/jenkins/my-tree/branches` | 我的分支（按 org/repo） | JWT |
| GET | `/api/permissions/jenkins/my-tree/full` | 我的权限树（缓存/重建） | JWT |
| GET | `/api/permissions/jenkins/check/:organization/:branch` | 检查分支权限 | JWT |
| GET | `/api/permissions/jenkins/tree` | 全量权限树（Admin） | JWT + Admin |
| GET | `/api/permissions/jenkins/users/role/:role` | 按角色查用户 | JWT + Admin |
| GET | `/api/permissions/jenkins/:userId` | 获取用户 Jenkins 权限 | JWT + Admin |
| POST | `/api/permissions/jenkins/assign` | 分配权限（层级覆盖） | JWT + Admin |
| POST | `/api/permissions/jenkins/copy` | 拷贝权限 | JWT + Admin |
| GET | `/api/permissions/jenkins/user-tree/:userId/organizations` | 懒加载组织 | JWT + Admin |
| GET | `/api/permissions/jenkins/user-tree/:userId/organizations/:org/repositories` | 懒加载仓库 | JWT + Admin |
| GET | `/api/permissions/jenkins/user-tree/:userId/organizations/:org/repositories/:repo/branches` | 懒加载分支 | JWT + Admin |

### 10.4 项目权限接口
| 方法 | 路径 | 说明 | 鉴权 |
|:---|:---|:---|:---|
| GET | `/api/permissions/projects/user/:userId/summary` | 获取用户项目权限摘要 | JWT + Admin |
| POST | `/api/permissions/projects/grant` | 授予项目模块权限 | JWT + Admin |
| POST | `/api/permissions/projects/revoke` | 撤销项目模块权限 | JWT + Admin |

> **注意**：前端不允许直接调用创建工单接口，用户注册/管理工单通过用户管理接口（如 `POST /api/users`、`PUT /api/users/:id`）内部自动创建。

### 10.5 系统配置
| 方法 | 路径 | 说明 | 鉴权 |
|:---|:---|:---|:---|
| GET | `/api/user/system-config` | 获取配置（为空时返回默认值） | JWT |
| PUT | `/api/user/system-config` | 更新配置 | JWT |

---

## 11. 业务流程

### 11.1 登录流程
```mermaid
sequenceDiagram
    participant FE as 前端
    participant UA as rmdc-user-auth
    
    FE->>UA: GET /api/auth/rsa/public-key
    UA-->>FE: 公钥
    FE->>UA: POST /api/auth/login (encrypted_password)
    UA->>UA: RSA 解密 + bcrypt 校验
    UA->>UA: 检查账户状态/有效期/密码过期
    UA->>UA: 生成 JWT(4h)
    UA-->>FE: token + userDTO + 附加标识
    
    Note over FE,UA: 附加标识：<br/>must_change_password<br/>password_expire_days<br/>account_expire_days
    
    alt must_change_password = true
        FE->>FE: 跳转强制改密页面
        FE->>UA: PUT /api/user/password/force-change
        UA->>UA: 更新密码,重置过期时间
        UA-->>FE: 改密成功
    end
```

### 11.2 用户注册工单
```mermaid
sequenceDiagram
    participant User as 已登录用户
    participant UA as rmdc-user-auth
    participant WP as rmdc-work-procedure
    participant SA as SuperAdmin

    User->>UA: POST /api/users (创建用户)
    UA->>UA: 权限检查：可注册该角色？
    UA->>UA: 创建用户(status=disabled, 默认密码)
    UA->>UA: 设置 account_expires_at
    UA->>UA: 设置 must_change_password = true
    UA->>WP: CreateWorkflow(user_registration, pending_review)
    WP-->>UA: workflow_id
    UA-->>User: 返回成功

    WP->>SA: 通知待审批

    alt 审批通过
        SA->>WP: approve
        WP->>UA: ActivateUser
        UA->>UA: status = active
    else 打回
        SA->>WP: return
        WP->>User: 通知修改
        User->>UA: PUT /api/users/:id
        User->>WP: resubmit
    else 撤销
        User->>WP: revoke
        WP->>UA: DeletePendingUser
        UA->>UA: DELETE (status=disabled)
    end
```

### 11.3 用户管理工单

> **重要**：前端不允许直接调用创建工单接口，工单由用户管理接口内部自动创建。

```mermaid
sequenceDiagram
    participant Operator as 操作人
    participant UA as rmdc-user-auth
    participant WP as rmdc-work-procedure
    participant SA as SuperAdmin

    Operator->>UA: PUT /api/users/:id (修改用户)
    Note right of Operator: 或 POST /api/users/:id/enable|disable|delete
    UA->>UA: CheckManagementPermission
    UA->>UA: 记录原始数据快照
    UA->>WP: CreateWorkflow(user_management)
    WP-->>UA: workflow_id
    UA-->>Operator: 返回成功

    WP->>SA: 通知待审批

    alt 审批通过
        SA->>WP: approve
        WP->>UA: ExecuteUserManagement
        UA->>UA: 执行操作(update/enable/disable/delete)
    else 打回
        SA->>WP: return
        WP->>Operator: 通知修改后重新提交
    end
```

---

## 12. 安全与合规

- **传输安全**：登录密码必须使用 RSA-OAEP(SHA-256, 2048) 加密；禁止明文密码传输。
- **存储安全**：密码使用 bcrypt；RSA 私钥仅存 DB，不下发前端；敏感字段不外露。
- **账户状态**：仅 active 用户可通过 JWT 校验；locked/disabled 一律拒绝。
- **密码策略**：
  - 默认 3 个月过期；修改/创建均刷新过期时间
  - 注册返回 disabled，需审批激活
  - 首次登录或密码重置后强制修改密码
- **账户有效期**：非 SuperAdmin 创建的用户必须设置有效期，过期后无法登录
- **Token**：HS256，4h 过期；无刷新，需重登；超时后自动失效。
- **权限检查**：SuperAdmin 全通；Admin 只能管理/授权 normal/third；权限分配需校验授予者是否具备权限。
- **"谁注册谁管理"**：非 SuperAdmin 只能管理自己注册的用户
- **TODO**：登录失败次数与锁定策略尚未实现；Watchdog 权限检查待补全。

---

## 13. 相关文档

| 文档 | 说明 |
|:---|:---|
| [用户认证PRD](1-user-auth-PRD.md) | 产品需求文档 |
| [用户权限设计](权限设计部分/3-用户部分-权限设计.md) | 用户注册管理权限设计 |
| [项目管理DDS](../4-rmdc-project-management/2-rmdc-project-management-DDS.md) | 参考文档结构（项目工单流程） |
| [工单模块DDS](../7-rmdc-work-procedure/1-rmdc-work-procedure-DDS.md) | 工单流程设计 |
