外观
账号与登录
本文讲管理端的鉴权配置与操作:静态 admin token、管理员账号体系(浏览器登录)、Turnstile 人机校验、会话管理。安全模型的设计依据见 ../internals/security.md,端点契约见 ../reference/api.md。
两种 admin 凭据
admin API(/admin/*、/ui/*)无差别接受两种 Bearer 凭据(apps/control-server-ts/src/auth.ts:23-48):
| 凭据 | 适用 | 来源 |
|---|---|---|
| 静态 admin token | 脚本 / 自动化 / curl | 主面 wrangler secret put ADMIN_TOKEN;温备面 control-server.toml / DN42_CONTROL_ADMIN_TOKEN |
| 账号会话令牌 | 浏览器(Web UI 登录) | POST /auth/login 签发 |
fail-closed:ADMIN_TOKEN 未配置时 admin API 整体 403(不会因缺配置而敞开)。审计日志以 principal.identity 区分两种凭据的操作者。
账号体系
- 密码用 argon2id 散列入库(
admin_users表);对不存在的用户名也执行一次对照校验,抹平时间侧信道。 - 会话令牌随机生成,DB 只存 sha256(
admin_sessions表),TTL 默认 24h(SESSION_TTL_SECONDS);改密吊销该账号全部会话。 - 登录必须通过 Cloudflare Turnstile 服务端硬校验(失败 400);
TURNSTILE_SECRET_KEY未配置时登录 400(fail-closed)。 - 登录限速:同用户名或同来源 IP 连续失败 5 次、15 分钟窗口 → 429。主面限速状态落 KV(最终一致),温备面在进程内。
首个管理员:惰性引导
Workers 没有启动期,首个账号在登录时惰性引导(src/routes/auth.ts:95-98):
wrangler secret put BOOTSTRAP_ADMIN,值为user:password(src/services/adminAccounts.ts:128-141)。- 用该用户名密码走一次正常登录——仅当
admin_users表为空时创建账号,幂等;表非空时该 secret 不再生效。 - 引导完成后建议改密(见下),并可考虑清掉
BOOTSTRAP_ADMINsecret。
登录与改密
bash
# 登录(Web UI 内置此流程;直接调 API 需自行取得 Turnstile token)
curl -s -X POST https://api.natlan.io/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"username": "...", "password": "...", "turnstile_token": "..."}'
# → {"token": "...", ...}
# 改密(仅账号会话令牌可调,静态 admin token 不可)
curl -s -X POST https://api.natlan.io/api/v1/auth/password \
-H "Authorization: Bearer <会话令牌>" \
-H 'Content-Type: application/json' \
-d '{"current_password": "...", "new_password": "..."}'状态码矩阵:400 Turnstile 失败 / 401 凭据无效 / 403 fail-closed(服务端未配置)/ 429 尝试过多。错误 detail 措辞是与前端锁死的稳定契约,改动即破坏兼容。
配置清单
| 项 | 主面(TS) | 温备面(Python) |
|---|---|---|
| 静态 admin token | secret ADMIN_TOKEN | [auth] / DN42_CONTROL_ADMIN_TOKEN |
| Turnstile secret | secret TURNSTILE_SECRET_KEY | TOML [auth] 对应项 |
| 首账号引导 | secret BOOTSTRAP_ADMIN(user:password) | 同名语义 |
| 会话 TTL | var SESSION_TTL_SECONDS(默认 86400) | TOML 对应项 |
完整配置面见 ../reference/configuration.md。
Turnstile 域名单:Cloudflare 面板中 Turnstile widget 的允许域名必须包含 Web UI 的访问域名(如 console.natlan.io),否则前端拿不到有效 turnstile token,登录一律 400。