# auth Specification ## Purpose TBD - created by archiving change refactor-framework-cleanup. Update Purpose after archive. ## Requirements ### Requirement: Unified Authentication Middleware 系统 SHALL 提供统一的认证中间件,支持可配置的 Token 提取和验证。 #### Scenario: Token 验证成功 - **WHEN** 请求携带有效的 Token - **THEN** 中间件提取并验证 Token - **AND** 将用户信息同时设置到 Fiber Locals 和 Context - **AND** 请求继续执行 #### Scenario: Token 缺失 - **WHEN** 请求未携带 Token - **AND** 路径不在跳过列表中 - **THEN** 返回 AppError(CodeMissingToken) - **AND** 由全局 ErrorHandler 处理错误响应 #### Scenario: Token 无效 - **WHEN** 请求携带的 Token 无效或过期 - **THEN** 返回 AppError(CodeUnauthorized) - **AND** 由全局 ErrorHandler 处理错误响应 #### Scenario: 跳过路径 - **WHEN** 请求路径在 SkipPaths 配置中 - **THEN** 中间件跳过认证 - **AND** 请求直接继续执行 ### Requirement: User Context Management 认证中间件 SHALL 提供用户上下文管理函数,支持从 Context 获取用户信息。 #### Scenario: 获取用户 ID - **WHEN** 调用 GetUserIDFromContext(ctx) - **AND** 认证已通过 - **THEN** 返回当前用户的 ID #### Scenario: 检查 Root 用户 - **WHEN** 调用 IsRootUser(ctx) - **THEN** 返回当前用户是否为 Root 用户 #### Scenario: 设置用户到 Fiber Context - **WHEN** 调用 SetUserToFiberContext(c, userInfo) - **THEN** 用户信息被设置到 Fiber Locals - **AND** 用户信息被设置到请求 Context(供 GORM 等使用) ### Requirement: Auth Middleware Configuration 认证中间件 SHALL 支持灵活的配置选项。 #### Scenario: 自定义 Token 提取 - **WHEN** 配置了 TokenExtractor 函数 - **THEN** 使用自定义函数从请求中提取 Token #### Scenario: 默认 Token 提取 - **WHEN** 未配置 TokenExtractor - **THEN** 从 Authorization Header 提取 Bearer Token #### Scenario: 自定义验证函数 - **WHEN** 配置了 Validator 函数 - **THEN** 使用自定义函数验证 Token 并返回用户信息 ### Requirement: 启动时自动初始化默认管理员 系统在 API 服务启动时 SHALL 检查数据库是否存在超级管理员账号,如果不存在则自动创建默认管理员账号。 **业务规则**: - 检查条件:`user_type = 1`(超级管理员)且未被软删除的账号 - 仅在不存在时创建,存在管理员时跳过 - 默认账号信息读取优先级: 1. **配置文件优先**:读取 `config.yaml` 的 `default_admin` 配置节 2. **代码默认值**:如果配置文件未提供,使用代码内置常量 - 代码内置默认值: - 用户名:`admin` - 密码:`Admin@123456`(bcrypt 哈希存储) - 手机号:`13800000000` - 用户类型:`1`(超级管理员) - 状态:`1`(启用) - 初始化失败不中断服务启动(记录错误日志,降级处理) #### Scenario: 空数据库首次启动(使用代码默认值) - **WHEN** API 服务启动且数据库中不存在任何超级管理员账号 - **AND** 配置文件未提供 `default_admin` 配置 - **THEN** 系统使用代码内置默认值创建管理员账号 - **AND** 用户名为 `admin`,密码为 `Admin@123456`,手机号为 `13800000000` - **AND** 记录日志:"已创建默认管理员账号: admin(使用代码默认值)" - **AND** 创建的账号可以正常使用(密码验证通过) #### Scenario: 空数据库首次启动(使用配置文件) - **WHEN** API 服务启动且数据库中不存在任何超级管理员账号 - **AND** 配置文件提供了 `default_admin` 配置 - **THEN** 系统使用配置文件中的值创建管理员账号 - **AND** 用户名、密码、手机号均从配置文件读取 - **AND** 记录日志:"已创建默认管理员账号: {username}(使用配置文件)" - **AND** 创建的账号可以正常使用(配置的密码验证通过) #### Scenario: 已有管理员时启动 - **WHEN** API 服务启动且数据库中已存在至少一个超级管理员账号 - **THEN** 系统跳过创建默认管理员 - **AND** 记录日志:"检测到已有管理员账号,跳过初始化" - **AND** 不创建任何新账号 #### Scenario: 用户名或手机号冲突 - **WHEN** API 服务启动且尝试创建默认管理员 - **AND** 数据库中已存在用户名为 `admin` 或手机号为 `13800000000` 的账号(非超级管理员) - **THEN** 系统创建失败 - **AND** 记录错误日志:"创建默认管理员失败: 用户名或手机号已存在" - **AND** 不中断服务启动(降级处理) #### Scenario: 初始化执行时机 - **WHEN** API 服务执行启动流程 - **THEN** 管理员初始化在以下时机执行: 1. 所有组件(Store、Service、Handler)初始化完成后 2. 注册路由前 3. 服务器开始监听前 - **AND** 确保 AccountStore 可用时才执行初始化 ### Requirement: 默认管理员配置支持 系统 SHALL 支持通过配置文件自定义默认管理员账号信息,配置文件优先级高于代码默认值。 **配置格式**: ```yaml default_admin: username: "admin" # 可选,默认 "admin" password: "Admin@123456" # 可选,默认 "Admin@123456" phone: "13800000000" # 可选,默认 "13800000000" ``` #### Scenario: 配置文件完整提供 - **WHEN** `config.yaml` 中配置了 `default_admin` 节 - **AND** 提供了 `username`、`password`、`phone` 三个字段 - **THEN** 系统读取配置文件的值 - **AND** 不使用代码默认值 - **AND** 创建管理员账号时使用配置的值 #### Scenario: 配置文件部分提供 - **WHEN** `config.yaml` 中配置了 `default_admin` 节 - **AND** 只提供了部分字段(如只配置了 `password`) - **THEN** 系统对已提供的字段使用配置值 - **AND** 对未提供的字段使用代码默认值 - **AND** 例如:配置了 `password: "MySecret123"`,但未配置 `username` 和 `phone` - 使用 `password = "MySecret123"` - 使用 `username = "admin"`(代码默认值) - 使用 `phone = "13800000000"`(代码默认值) #### Scenario: 配置文件未提供 - **WHEN** `config.yaml` 中未配置 `default_admin` 节 - **THEN** 系统使用代码内置默认值 - **AND** 用户名为 `admin` - **AND** 密码为 `Admin@123456` - **AND** 手机号为 `13800000000` #### Scenario: 配置验证 - **WHEN** 读取 `default_admin` 配置 - **THEN** 配置项为可选,不参与 `Validate()` 验证 - **AND** 允许配置为空或不存在 - **AND** 不阻止服务启动 ### Requirement: 默认管理员安全配置 系统 SHALL 使用足够复杂的默认密码,并记录管理员创建日志用于安全审计。 #### Scenario: 默认密码复杂度 - **WHEN** 创建默认管理员账号 - **THEN** 代码内置默认密码 SHALL 满足以下复杂度要求: - 长度 ≥ 12 位 - 包含大写字母、小写字母、数字、特殊字符 - 示例:`Admin@123456` #### Scenario: 审计日志记录 - **WHEN** 创建或跳过默认管理员账号 - **THEN** 系统记录审计日志到 `app.log` - **AND** 日志包含以下信息: - 操作时间 - 操作结果(创建成功/跳过/失败) - 创建的用户名(成功时) - 配置来源(配置文件/代码默认值) - 失败原因(失败时) - **AND** 不在日志中记录明文密码 ### Requirement: 系统账号创建内部接口 Account Service SHALL 提供内部方法用于系统初始化场景创建账号,绕过常规的用户上下文检查。 #### Scenario: 系统初始化创建账号 - **WHEN** 系统初始化需要创建内部账号(如默认管理员) - **THEN** 调用 `createSystemAccount(ctx, account)` 方法 - **AND** 该方法不检查当前用户 ID(允许 context 中无用户信息) - **AND** 保留用户名和手机号唯一性检查 - **AND** 密码使用 bcrypt 哈希存储 - **AND** 自动设置 creator 和 updater 为 0(系统创建) #### Scenario: 常规 API 请求不使用系统接口 - **WHEN** 通过 HTTP API 创建账号 - **THEN** 使用常规 `Create()` 方法 - **AND** 必须有当前用户上下文(user_id > 0) - **AND** 不允许调用 `createSystemAccount()` 方法(内部使用)