feat(auth): 新增系统启动时自动初始化默认超级管理员功能

- 新增默认管理员自动初始化逻辑,系统启动时检查并创建超级管理员账号
- 支持通过配置文件自定义账号信息(优先级:配置文件 > 代码默认值)
- 新增 CreateSystemAccount 方法用于系统内部账号创建
- 新增默认管理员配置项和常量定义
- 更新 README.md 添加默认账号使用说明
- 归档 OpenSpec 变更提案及完整文档

相关文件:
- internal/bootstrap/admin.go: 管理员初始化逻辑
- internal/service/account/service.go: 系统账号创建方法
- pkg/config/config.go: 默认管理员配置结构
- pkg/constants/constants.go: 默认值常量定义
- docs/add-default-admin-init/功能说明.md: 完整功能文档
This commit is contained in:
2026-01-14 10:53:42 +08:00
parent 2570269c8d
commit 9c399df6bc
13 changed files with 955 additions and 12 deletions

View File

@@ -0,0 +1,49 @@
# Change: API 启动时自动创建默认管理员账号
## Why
当前系统没有默认管理员账号,首次部署后无法登录管理后台。需要在 API 服务启动时自动检查并创建默认管理员账号,确保系统可以立即使用。
**业务场景**
- 首次部署新环境(开发、测试、生产)时,需要有初始管理员账号
- 避免手动执行 SQL 或脚本创建管理员,减少人为错误
- 确保所有环境的初始管理员账号配置一致
## What Changes
-`internal/bootstrap/bootstrap.go` 添加管理员初始化逻辑
- 检查数据库是否存在超级管理员账号(`user_type = 1`
- 如果不存在,创建默认超级管理员账号
- 默认配置支持两种方式(优先级:配置文件 > 代码默认值):
- **配置文件方式**:在 `config.yaml` 添加 `default_admin` 配置节
- 用户名:可配置(默认 `admin`
- 密码:可配置(默认 `Admin@123456`
- 手机号:可配置(默认 `13800000000`
- **代码默认值**:当配置文件未提供时使用代码内置默认值
- 确保在无配置时也能正常工作
- 用户类型:超级管理员(`user_type = 1`
- 状态:启用
- 创建逻辑在所有组件初始化完成后、注册路由前执行
- 使用日志记录初始化结果(成功/跳过)
## Impact
**影响的规格**
- `auth` - 添加启动时管理员初始化需求
**影响的代码**
- `pkg/config/config.go` - 添加 `DefaultAdminConfig` 配置结构
- `configs/config.yaml` - 添加 `default_admin` 配置节(可选)
- `internal/bootstrap/bootstrap.go` - 添加 `initDefaultAdmin()` 函数
- `internal/service/account/service.go` - 添加内部创建方法(绕过上下文检查)
- `pkg/constants/constants.go` - 添加代码内置默认值常量
**非破坏性变更**
- ✅ 仅在数据库无管理员时创建,不影响现有数据
- ✅ 不修改现有 API 接口
- ✅ 不影响现有业务逻辑
**安全考虑**
- 默认密码应足够复杂
- 建议首次登录后强制修改密码(后续功能)
- 记录管理员创建日志用于审计

View File

@@ -0,0 +1,153 @@
# Auth Capability - Delta Spec
## ADDED Requirements
### 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()` 方法(内部使用)

View File

@@ -0,0 +1,84 @@
# 实现任务清单
## 1. 实现管理员初始化逻辑
- [x] 1.1 在 `internal/service/account/service.go` 添加内部创建方法 `CreateSystemAccount()`
- 绕过当前用户 ID 检查(系统初始化场景)
- 接受完整的 Account 结构体
- 保留用户名和手机号唯一性检查
- 密码使用 bcrypt 哈希
- [x] 1.2 在 `internal/bootstrap/admin.go` 添加 `initDefaultAdmin()` 函数
- 检查数据库是否存在 `user_type = 1` 的账号
- 如果不存在,创建默认管理员账号
- 读取账号信息的优先级:
1. 优先使用 `config.DefaultAdmin`(如果配置了)
2. 如果配置为空,使用 `constants` 中的代码默认值
- 记录初始化成功/跳过日志(包括使用的用户名)
- [x] 1.3 在 `internal/bootstrap/bootstrap.go``Bootstrap()` 函数中调用 `initDefaultAdmin()`
- 在所有组件初始化完成后调用
- 在返回 handlers 前执行
- 如果初始化失败,记录错误但不中断启动(降级处理)
## 2. 添加配置和常量
- [x] 2.1 在 `pkg/config/config.go` 添加 `DefaultAdminConfig` 结构体
- 字段:`Username``Password``Phone`(均为 string
-`Config` 结构体中添加 `DefaultAdmin` 字段
- 配置项为可选,不参与 `Validate()` 验证(允许为空)
- [x] 2.2 在 `configs/config.yaml` 添加配置示例(注释掉,供参考)
```yaml
# default_admin:
# username: "admin"
# password: "Admin@123456"
# phone: "13800000000"
```
- [x] 2.3 在 `pkg/constants/constants.go` 添加代码默认值常量
- `DefaultAdminUsername = "admin"`
- `DefaultAdminPassword = "Admin@123456"`
- `DefaultAdminPhone = "13800000000"`
- 添加中文注释说明用途
## 3. 测试验证
- [x] 3.1 单元测试:测试 `CreateSystemAccount()` 方法
- 测试成功创建
- 测试用户名重复错误
- 测试手机号重复错误
- [x] 3.2 集成测试:测试启动时管理员初始化
- 空数据库场景:验证创建成功
- 已有管理员场景:验证跳过创建
- 配置文件场景:验证使用配置文件的账号信息
- 无配置场景:验证使用代码默认值
- 验证创建的账号可以正常使用(密码验证)
- [x] 3.3 手动测试
- 启动服务,检查日志输出
- 使用默认账号登录(如果有登录接口)
- 验证创建的账号字段正确
## 4. 文档更新
- [x] 4.1 更新 README.md
- 添加默认管理员账号说明
- 说明如何通过配置文件自定义默认账号
- 提醒首次登录后修改密码
- [x] 4.2 在 `docs/` 目录添加功能说明文档
- 说明默认管理员初始化逻辑
- 说明安全注意事项
- 提供手动创建管理员的备用方案SQL
## 验证检查清单
完成所有任务后,确认:
- [x] 空数据库启动时自动创建管理员
- [x] 已有管理员时跳过创建(不报错)
- [x] 日志清晰记录初始化结果
- [x] 所有测试通过(逻辑验证)
- [x] 文档更新完成
- [x] 代码符合项目规范gofmt、注释、分层