11 KiB
11 KiB
账号管理
本文说明 cdxs 当前账号管理功能的实现方式、调用机制和运行过程。
功能范围
账号管理主要覆盖以下能力:
- 从 Codex 原生
auth.json导入账号。 - 添加 API Key 账号。
- 列出所有已保存账号。
- 查看当前账号。
- 查看指定账号详情。
- 删除指定账号。
- 将指定账号切换为当前账号并写入目标
auth.json。
核心文件
src/main.rs:CLI 入口,负责把命令分发到具体模块。src/cli.rs:定义账号相关命令和参数。src/account.rs:账号管理主逻辑。src/config_store.rs:cdxs.toml的数据模型、加载、保存和查询。src/auth_file.rs:Codex 原生auth.json的读取和写入。src/paths.rs:解析CODEX_HOME、auth.json、cdxs.toml路径。src/atomic.rs:写入配置或认证文件前备份,并使用原子写入。src/jwt.rs:从 OAuthid_token中解析邮箱、计划、组织等账号元数据。src/token.rs:切换 OAuth 账号前按需刷新 token。
数据保存方式
cdxs 自己的账号状态保存在当前 CODEX_HOME 下的 cdxs.toml:
<CODEX_HOME>\cdxs.toml
如果没有设置 CODEX_HOME,默认使用:
%USERPROFILE%\.codex
账号列表保存在 Store.accounts 中,当前账号 ID 保存在:
Store.meta.current_account_id
每个账号使用 Account 结构保存,关键字段包括:
id:稳定账号 ID。email:显示用邮箱或 API Key 虚拟邮箱。auth_mode:oauth或api_key。tokens:OAuth 账号的 token。openai_api_key:API Key 账号的 key。api_base_url:API Key 账号的可选 base URL。plan_type:账号套餐类型。account_id:OAuth 账号 ID。organization_id:OAuth 组织 ID。quota:最近一次配额查询结果。requires_reauth:OAuth refresh 失败后标记是否需要重新登录。
账号 ID 生成原理
账号 ID 由 account.rs 中的 stable_id 生成。
OAuth 账号使用以下信息生成稳定 ID:
- 固定前缀:
oauth - 邮箱
account_idorganization_id
API Key 账号使用以下信息生成稳定 ID:
- 固定前缀:
apikey - API Key
base_url
生成方式是对这些字段做 SHA-256,然后取前 16 位十六进制字符串:
oauth_xxxxxxxxxxxxxxxx
apikey_xxxxxxxxxxxxxxxx
这样重复导入同一个账号时,会更新原有记录,而不是创建重复账号。
命令调用机制
账号相关命令由 src/cli.rs 定义,再由 src/main.rs 分发到 src/account.rs。
flowchart TD
A[用户执行 cdxs 命令] --> B[Cli::parse]
B --> C[src/main.rs match Commands]
C --> D{账号相关命令}
D -->|cdxs import auth| E[account::import_auth]
D -->|cdxs account add-api-key| F[account::add_api_key]
D -->|cdxs list / account list| G[account::list_accounts]
D -->|cdxs account current| H[account::current_account]
D -->|cdxs account show| I[account::show_account]
D -->|cdxs account remove| J[account::remove_account]
D -->|cdxs switch| K[account::switch_account]
导入 auth.json 运行过程
命令:
cdxs import auth
可选参数:
cdxs import auth --file <auth.json路径>
cdxs import auth --codex-home <路径>
cdxs import auth --switch
运行过程:
- 解析主配置 home,也就是保存
cdxs.toml的位置。 - 解析来源 home,用于定位要导入的
auth.json。 - 调用
auth_file::read_auth_file读取并解析auth.json。 - 调用
account_from_auth判断是 OAuth 账号还是 API Key 账号。 - OAuth 账号会解析 token,并从
id_token中读取邮箱、计划、账号 ID、组织 ID。 - API Key 账号会读取
OPENAI_API_KEY和可选 base URL。 - 生成稳定账号 ID。
- 调用
Store::upsert_account写入或更新账号。 - 如果带
--switch,同时写入目标 home 的auth.json,并设置当前账号。 - 调用
Store::save保存cdxs.toml。
sequenceDiagram
participant U as 用户
participant M as main.rs
participant A as account.rs
participant P as paths.rs
participant AF as auth_file.rs
participant S as config_store.rs
participant J as jwt.rs
U->>M: cdxs import auth
M->>A: import_auth(file, codex_home, switch)
A->>P: codex_home(None)
P-->>A: 配置 home
A->>P: codex_home(codex_home)
P-->>A: 来源 home
A->>AF: read_auth_file(auth_path)
AF-->>A: CodexAuthFile
A->>A: account_from_auth
alt OAuth 账号
A->>J: decode_payload(id_token)
J-->>A: email / plan / account_id / organization_id
A->>A: oauth_account
else API Key 账号
A->>AF: extract_api_key / api_base_url
AF-->>A: key / base_url
A->>A: api_key_account
end
A->>S: Store::load
S-->>A: Store
A->>S: upsert_account
opt --switch
A->>AF: write_account_to_auth
A->>A: 设置 current_account_id
end
A->>S: save
S-->>U: 导入完成
添加 API Key 账号运行过程
命令:
cdxs account add-api-key --key sk-...
可选参数:
cdxs account add-api-key --key sk-... --base-url https://example.com/v1
cdxs account add-api-key --key sk-... --switch
运行过程:
- 解析当前
CODEX_HOME。 - 加载
cdxs.toml。 - 校验 API Key 非空。
- 根据 API Key 和 base URL 生成稳定账号 ID。
- 生成显示用邮箱,格式类似
api-key-xxxxxxxx。 - 调用
Store::upsert_account保存账号。 - 如果带
--switch,写入当前 home 的auth.json。 - 保存
cdxs.toml。
flowchart TD
A[cdxs account add-api-key] --> B[paths::codex_home]
B --> C[Store::load]
C --> D[api_key_account]
D --> E[stable_id]
E --> F[Store::upsert_account]
F --> G{是否 --switch}
G -->|是| H[auth_file::write_account_to_auth]
G -->|否| I[跳过 auth.json 写入]
H --> J[Store::save]
I --> J
列出账号运行过程
命令:
cdxs list
cdxs account list
JSON 输出:
cdxs list --json
cdxs account list --json
运行过程:
- 解析当前
CODEX_HOME。 - 加载
cdxs.toml。 - 如果
--json,直接输出store.accounts的 JSON。 - 如果不是 JSON,按表格输出账号 ID、邮箱、认证模式、套餐和配额。
- 当前账号会用
*标记。
查看当前账号运行过程
命令:
cdxs account current
JSON 输出:
cdxs account current --json
运行过程:
- 加载
cdxs.toml。 - 读取
Store.meta.current_account_id。 - 如果没有当前账号,输出未设置账号。
- 如果当前账号 ID 不存在,返回错误。
- 找到账号后输出详情或 JSON。
查看指定账号运行过程
命令:
cdxs account show <账号ID或邮箱前缀>
查找账号使用 Store::find_account,支持三种匹配方式:
- 完整账号 ID。
- 完整邮箱。
- 邮箱前缀。
运行过程:
- 加载
cdxs.toml。 - 调用
find_account查找账号。 - 找不到则返回错误。
- 找到后输出详情或 JSON。
删除账号运行过程
命令:
cdxs account remove <账号ID或邮箱前缀>
运行过程:
- 加载
cdxs.toml。 - 用账号 ID、邮箱或邮箱前缀查找账号。
- 从
Store.accounts中删除该账号。 - 如果该账号是当前账号,清空
current_account_id。 - 如果有 home 绑定该账号,清空对应
bound_account_id。 - 保存
cdxs.toml。
flowchart TD
A[cdxs account remove] --> B[Store::load]
B --> C[Store::find_account]
C --> D{是否存在}
D -->|否| E[返回账号不存在错误]
D -->|是| F[accounts.retain 删除账号]
F --> G{是否当前账号}
G -->|是| H[清空 current_account_id]
G -->|否| I[保持 current_account_id]
H --> J[清空 homes 中相关 bound_account_id]
I --> J
J --> K[Store::save]
切换账号运行过程
命令:
cdxs switch <账号ID或邮箱前缀>
可选指定目标 home:
cdxs switch <账号> --codex-home <路径>
运行过程:
- 加载主配置 home 的
cdxs.toml。 - 解析目标 home,用于确定要写入哪个
auth.json。 - 用账号 ID、邮箱或邮箱前缀查找账号。
- 如果是 OAuth 账号,调用
token::refresh_account_if_needed检查 access token 是否即将过期。 - 如果 token 需要刷新,则先刷新并更新
cdxs.toml中的账号 token。 - 调用
auth_file::write_account_to_auth把账号写入目标 home 的auth.json。 - 更新该账号的
last_used_at。 - 设置
Store.meta.current_account_id。 - 保存
cdxs.toml。
sequenceDiagram
participant U as 用户
participant M as main.rs
participant A as account.rs
participant S as config_store.rs
participant T as token.rs
participant AF as auth_file.rs
U->>M: cdxs switch <account>
M->>A: switch_account
A->>S: Store::load
S-->>A: Store
A->>S: find_account
S-->>A: Account
A->>T: refresh_account_if_needed
alt OAuth token 即将过期
T->>T: refresh_account
T-->>A: 已更新 tokens
else 不需要刷新或 API Key
T-->>A: 无需刷新
end
A->>AF: write_account_to_auth
AF-->>A: 写入 auth.json
A->>A: 更新 last_used_at/current_account_id
A->>S: save
S-->>U: 切换完成
auth.json 写入规则
账号切换或带 --switch 保存账号时,会调用 auth_file::write_account_to_auth。
OAuth 账号写入格式:
{
"OPENAI_API_KEY": null,
"tokens": {
"id_token": "...",
"access_token": "...",
"refresh_token": "...",
"account_id": "..."
},
"last_refresh": "..."
}
API Key 账号写入格式:
{
"auth_mode": "apikey",
"OPENAI_API_KEY": "sk-..."
}
写入安全机制
cdxs.toml 和 auth.json 写入时都使用同一套安全机制:
- 如果目标文件已存在,先备份到:
<CODEX_HOME>\cdxs-backups\
- 写入时先写到同目录临时文件:
.<原文件名>.tmp
- 再用 rename 替换目标文件。
这样可以降低写入中断导致配置文件损坏的风险。
当前实现边界
switch --apply-fingerprint当前只输出提示,实际不会应用设备指纹。- API Key 账号没有 OAuth token,也不会参与 token refresh。
- 账号查找支持邮箱前缀,但如果多个邮箱前缀相同,当前实现会返回第一个匹配项。
remove_account只删除cdxs.toml中的账号记录,不会主动清理已经写入某个 home 的auth.json。