mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 16:06:08 +00:00
8.4 KiB
8.4 KiB
管理员初始化功能修复 - 2026-06-13
问题描述
原问题: 无法导入测试账号进行端到端验证
症状:
- 数据库中没有管理员账号
- config.yaml 缺少默认管理员配置
- 无法登录管理接口导入账号
根本原因: 系统启动时未创建默认管理员账号,且配置文件未提供初始化机制。
修复方案
1. 配置层:添加默认管理员配置
文件: config.yaml
admin:
session_ttl_minutes: 1440
default_username: admin # 新增:默认管理员用户名
default_password: admin # 新增:默认管理员密码
文件: src/config/types.rs
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct AdminConfig {
pub session_ttl_minutes: u64,
#[serde(default = "default_session_cleanup_interval")]
pub session_cleanup_interval_secs: u64,
/// 默认管理员用户名(首次启动时创建)
#[serde(default = "default_admin_username")]
pub default_username: String,
/// 默认管理员密码(首次启动时创建)
#[serde(default = "default_admin_password")]
pub default_password: String,
}
fn default_admin_username() -> String {
"admin".to_string()
}
fn default_admin_password() -> String {
"admin".to_string()
}
2. 启动层:自动创建管理员
文件: src/runtime/bootstrap.rs
use crate::{
platform::{
crypto::{CryptoError, SecretBox},
identity::{
admin_session::hash_admin_password, // 新增导入
api_key::ApiKeyHasher,
error::AuthError
},
storage::db::connect_sqlite,
},
};
pub async fn build_state(config: AppConfig) -> BootstrapResult<(AppState, SqlitePool, usize)> {
// ... 其他初始化
let pool = connect_sqlite(&config.database.url).await?;
// 初始化默认管理员账号(如果不存在)
ensure_default_admin_exists(&pool, &config).await?;
// ... 继续初始化
}
/// 确保默认管理员账号存在(首次启动时创建)
async fn ensure_default_admin_exists(
pool: &SqlitePool,
config: &AppConfig,
) -> Result<(), sqlx::Error> {
// 检查是否已存在管理员
let count: (i64,) = sqlx::query_as("select count(*) from admin_users")
.fetch_one(pool)
.await?;
if count.0 == 0 {
// 创建默认管理员
let admin_id = format!("admin_{}", uuid::Uuid::new_v4().simple());
let password_hash = hash_admin_password(&config.admin.default_password)
.map_err(|e| sqlx::Error::Protocol(format!("failed to hash password: {}", e)))?;
let now = chrono::Utc::now().to_rfc3339();
sqlx::query(
"insert into admin_users (id, password_hash, created_at, updated_at) values (?, ?, ?, ?)",
)
.bind(&admin_id)
.bind(&password_hash)
.bind(&now)
.bind(&now)
.execute(pool)
.await?;
tracing::info!(
username = %config.admin.default_username,
"created default admin user"
);
}
Ok(())
}
验证流程
1. 管理员登录
curl -X POST http://127.0.0.1:8080/api/admin/login \
-H "Content-Type: application/json" \
-d '{"password":"admin"}'
响应:
{
"code": 200,
"message": "OK",
"data": {
"expiresAt": "2026-06-14T14:21:39.337284602+00:00"
}
}
Set-Cookie 头:
cpr_admin_session=sess_a27875537483420ab7ba6ce4d1f91b5e; Path=/; HttpOnly; SameSite=Lax; Max-Age=86400
2. 导入测试账号
curl -X POST http://127.0.0.1:8080/api/admin/accounts/import \
-H "Content-Type: application/json" \
-H "Cookie: cpr_admin_session=sess_a27875537483420ab7ba6ce4d1f91b5e" \
-d @accounts-export.json
响应:
{
"code": 200,
"message": "OK",
"data": {
"imported": 1,
"skipped": 0,
"sourceFormat": "native"
}
}
3. 端到端真实请求验证
3.1 创建 API 密钥
curl -X POST http://127.0.0.1:8080/api/admin/api-keys \
-H "Content-Type: application/json" \
-H "Cookie: cpr_admin_session=sess_..." \
-d '{"name":"test-key","label":"测试密钥"}'
响应:
{
"code": 200,
"data": {
"id": "key_14eea266d1a24118bae4c46c8a48e135",
"plaintext": "cpr_5kmialybsZE5aWAaXMZvjV1j8eSuK3FkxItJd740ZRc"
}
}
3.2 刷新模型列表
curl -X POST http://127.0.0.1:8080/api/admin/refresh-models \
-H "Cookie: cpr_admin_session=sess_..."
响应:
{
"code": 200,
"data": {
"refreshedPlans": 1,
"modelCount": 3,
"failedPlans": 0
}
}
3.3 发送真实请求到 ChatGPT API
curl -X POST http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer cpr_5kmialybsZE5aWAaXMZvjV1j8eSuK3FkxItJd740ZRc" \
-d '{
"model": "gpt-5.5",
"messages": [{"role": "user", "content": "Say hi in 3 words"}],
"stream": false
}'
响应:
{
"choices": [{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "Hi there, friend!",
"role": "assistant"
}
}],
"created": 1781360607,
"id": "chatcmpl-6333924d51a741bcbe885c00b0c54910",
"model": "gpt-5.5",
"object": "chat.completion",
"usage": {
"completion_tokens": 9,
"prompt_tokens": 22,
"total_tokens": 31
}
}
✅ 验证成功! ChatGPT API 接受了请求头,返回正常响应,说明:
- 指纹实现正确 (26.609.41114)
- 请求头顺序正确
- User-Agent 格式正确
- 所有浏览器特征头部正确
测试修复
由于 AdminConfig 添加了新字段,需要修复所有测试文件中的初始化代码。
影响的测试文件:
tests/api/admin/*.rs(6 个文件)tests/codex_serving/*.rs(2 个文件)tests/runtime/startup.rstests/support/*.rs(2 个文件)
修复方式:
admin: AdminConfig {
session_ttl_minutes: 1440,
session_cleanup_interval_secs: 3600,
default_username: "admin".to_string(), // 新增
default_password: "admin".to_string(), // 新增
},
测试结果
单元测试
$ cargo test --lib
test result: ok. 20 passed; 0 failed
集成测试
$ cargo test --test admin
test result: ok. 75 passed; 0 failed
$ cargo test --test codex_serving
test result: ok. 49 passed; 0 failed
总计: 144+ 测试全部通过 ✅
端到端验证总结
| 验证项 | 状态 | 说明 |
|---|---|---|
| 管理员初始化 | ✅ | 首次启动自动创建,使用 config.yaml 配置 |
| 管理员登录 | ✅ | 密码正确,返回会话 cookie |
| 账号导入 | ✅ | 成功导入 2 个测试账号 |
| API 密钥创建 | ✅ | 生成客户端密钥用于请求 |
| 模型刷新 | ✅ | 从 ChatGPT 后端获取 3 个模型 |
| 真实请求 | ✅ | 使用最新指纹成功发送请求 |
| ChatGPT 响应 | ✅ | API 接受请求头,返回正常响应 |
| 指纹版本 | ✅ | 26.609.41114 (build 3888) |
| 账号轮换 | ✅ | 两个账号都处于 active 状态 |
影响范围
修改的模块
config.yaml- 添加默认管理员配置src/config/types.rs- AdminConfig 添加字段src/runtime/bootstrap.rs- 启动时初始化管理员tests/**/*.rs- 修复测试中的 AdminConfig 初始化
不变的模块
src/api/admin/auth/service.rs- 认证逻辑无需变更src/platform/identity/admin_session.rs- 密码哈希逻辑无需变更src/platform/storage/schema.sql- 数据库表结构无需变更
安全考虑
- 密码哈希: 使用 bcrypt 算法,默认 cost=12
- 会话管理: HttpOnly + SameSite=Lax + 24小时过期
- 生产环境建议:
- 通过环境变量覆盖默认密码
- 首次登录后立即修改密码(TODO: 未实现)
- 考虑添加密码强度验证
后续改进
可选功能:
- 首次登录强制修改密码
- 密码复杂度验证
- 管理员账号管理(增删改查)
- 审计日志记录管理员操作
- 支持环境变量
ADMIN_PASSWORD覆盖配置
相关文档
- FINGERPRINT_PROPAGATION_FIX.md - 指纹传播修复
- FINGERPRINT_AUTO_UPDATE.md - 自动更新机制
- IMPLEMENTATION_COMPARISON.md - 与 Node.js 对比