# 后台管理服务设计 日期:`2026-04-23` 更新:`2026-04-30` > 状态说明:本文件中的管理员鉴权、`/admin/api/*` 管理接口、数据库概览与受控 API 调试设计继续有效;同源内嵌 HTML/CSS/JS 后台页面已废弃。后续后台 UI 迁移到独立前端工程,当前 `api-server` 不再挂载 `GET /admin` 页面入口。独立后台前端的产品边界见 [`../prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md`](../prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md),技术方案见 [`ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md`](./ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。 ## 1. 目标 为当前 Rust `api-server` 增加一套同源后台管理服务,满足以下首版目标: 1. 支持管理员用户名密码登录。 2. 支持独立的管理员鉴权,不允许普通玩家 JWT 越权访问。 3. 支持在后台查看当前服务与数据库概览信息。 4. 支持在后台测试当前 `api-server` 已挂载接口。 5. 保持管理能力继续收口在 `server-rs`,管理 UI 由独立后台前端工程承接。 ## 2. 背景与约束 当前仓库已具备: 1. Rust `api-server` 主链。 2. 基于 JWT + refresh session 的普通用户登录体系。 3. `SpacetimeDB + spacetime-client` 的主数据面。 本次后台管理服务必须继续遵守: 1. 后端统一落在 `server-rs`,不回退到 `server-node`。 2. 不额外新起独立管理服务进程。 3. 管理 API 继续作为受保护管理域挂载在 `api-server`。 4. 数据库信息必须尽量读取真实数据库侧信息,不能只展示硬编码假数据。 ## 3. 首版范围 ### 3.1 包含 1. `POST /admin/api/login`:管理员用户名密码登录。 2. `GET /admin/api/me`:当前管理员会话信息。 3. `GET /admin/api/overview`:服务与数据库概览。 4. `POST /admin/api/debug/http`:受控 HTTP 接口调试。 5. `POST /admin/api/profile/redeem-codes`:兑换码创建/更新。 6. `POST /admin/api/profile/redeem-codes/disable`:兑换码停用。 7. 基于 Bearer JWT 的管理员鉴权中间件。 ### 3.2 不包含 1. 多角色管理员体系。 2. 管理员 refresh cookie / 多端会话管理。 3. 后台直接写库、删库、执行 reducer。 4. 任意 SQL 执行器。 5. `api-server` 内嵌 HTML/CSS/JS 后台页面。 ## 4. 总体方案 ### 4.1 部署形态 后台管理服务直接挂载在现有 `server-rs/crates/api-server` 内,作为同一个 Axum 进程的一部分。 原因: 1. 当前 `api-server` 已具备配置、JWT、错误包裹、日志与同源路由能力。 2. 后台本质上是服务运维与调试面,不值得单独再起一个网关或 BFF。 3. 同源可以避免开发期额外 CORS 和 cookie 域问题。 ### 4.2 页面形态 后台管理页面不再由 `api-server` 直接返回内嵌 HTML/CSS/JS。`api-server` 仅保留管理 API,页面由独立后台前端工程调用这些接口。 原因: 1. 管理 UI 需要独立演进,不应继续堆在 Rust 源码字符串中。 2. `server-rs` 继续负责鉴权、聚合和写操作,符合前端只做表现的工程约束。 3. 删除 `GET /admin` 后,当前服务访问该路径应返回 `404`。 ### 4.3 数据库信息来源 数据库概览不走本地 CLI shell,也不依赖前端直接访问数据库。 首版采用两类信息源: 1. 服务端配置与连接信息:来自 `api-server` 当前 `AppConfig`。 2. SpacetimeDB 真正的数据库元信息与表行数:由 `api-server` 通过 SpacetimeDB 官方 HTTP API 读取。 读取口径: 1. `/v1/database/{database}`:读取数据库基础信息。 2. `/v1/database/{database}/schema`:读取 schema 信息。 3. `/v1/database/{database}/sql`:对受控表执行 `SELECT COUNT(*)` 统计。 说明: 1. 首版只做只读概览,不暴露任意 SQL 输入。 2. 表清单由后端显式维护,避免用户在后台拼接任意查询。 ## 5. 管理员鉴权设计 ### 5.1 管理员账号来源 首版不复用普通玩家账号仓储,不把管理员账号混进 `module-auth` 用户表。 管理员账号来自环境变量: 1. `GENARRATIVE_ADMIN_USERNAME` 2. `GENARRATIVE_ADMIN_PASSWORD` 原因: 1. 管理员是平台运维身份,不等于玩家账号。 2. 首版目标是尽快落地可靠后台,不引入额外管理员表迁移。 3. 环境变量方案最适合当前阶段的单后台入口。 ### 5.2 管理员 JWT 后台登录成功后签发独立管理员 Bearer JWT。 claims 设计: 1. 继续复用 `platform-auth::AccessTokenClaims`。 2. `roles` 固定包含 `admin`。 3. `sub` 使用稳定管理员主体,例如 `admin:`。 4. `sid` 使用后台会话 ID。 5. 不写 refresh cookie。 ### 5.3 权限校验 新增 `require_admin_auth` 中间件,校验规则如下: 1. Bearer token 必须可被当前 JWT 配置正确验签。 2. `roles` 中必须包含 `admin`。 3. `sub` 必须匹配当前管理员配置主体。 普通用户 token 即使同样由本服务签发,只要不带 `admin` 角色,也一律拒绝访问后台接口。 ## 6. 后台页面设计 本节已由独立后台前端工程方案接管。历史同源页面曾包含三个主区域: 1. 登录卡片。 2. 数据库概览面板。 3. API 调试面板。 交互原则: 1. 页面简洁,不默认塞说明性长文案。 2. 移动端优先,窄屏下卡片改纵向堆叠。 3. API 调试结果在独立结果面板展示,不在按钮下方临时插一段文本。 ## 7. 数据库概览设计 `GET /admin/api/overview` 返回以下信息: 1. 当前服务监听信息。 2. 当前 `SpacetimeDB server/database` 配置。 3. `SpacetimeDB` 数据库基础信息。 4. 当前 schema 表清单。 5. schema 表清单对应的逐表行数统计。 表统计必须以 SpacetimeDB schema 返回的表名为唯一来源,`schemaTableNames` 的数量必须与 `tableStats` 的行数一致。后台服务只对 schema 中符合安全 SQL 标识符格式的表名发起 `SELECT COUNT(*)`,不提供任意 SQL 输入能力。 返回中的计数失败项必须带错误信息,不能静默吞掉。SpacetimeDB private 表或当前身份不可见的表可能在 `/sql` 下返回 `no such table` / `marked private`,这类项统一展示为“不可统计(private 或当前身份不可见)”,不作为整页读取失败处理。 ## 8. API 调试设计 `POST /admin/api/debug/http` 提供一个受控 HTTP 调试代理。 请求参数: 1. `method` 2. `path` 3. `headers` 4. `body` 限制: 1. 只允许访问当前服务同源相对路径。 2. 调试回环地址由服务端按当前 `bind_host` 解析;若服务监听在 `0.0.0.0` 或 `::`,后台自动改走 loopback,避免把通配监听地址直接当成调试目标。 2. 禁止调 `/admin/api/login` 本身,避免自套娃。 3. 禁止覆盖 `host`、`content-length` 等危险头。 4. 请求超时固定收口。 5. 返回调试结果时回显状态码、响应头、响应文本预览。 该能力用于验证当前服务端接口,不等价于通用代理工具。 ## 9. 配置项 新增以下环境变量: 1. `GENARRATIVE_ADMIN_USERNAME` 2. `GENARRATIVE_ADMIN_PASSWORD` 3. `GENARRATIVE_ADMIN_TOKEN_TTL_SECONDS` 默认策略: 1. 若未配置用户名或密码,则后台登录接口返回 `503`,独立后台前端自行展示未启用状态。 2. 默认管理员 token TTL 为 `4` 小时。 ## 10. 测试要求 至少覆盖: 1. 管理员登录成功。 2. 管理员密码错误返回 `401`。 3. 普通用户 token 访问后台接口返回 `403`。 4. 未登录访问后台接口返回 `401`。 5. 后台概览接口在未启用管理员配置时返回 `503`。 6. API 调试接口能成功访问 `/healthz`。 7. API 调试接口拒绝绝对 URL 和后台自身登录接口。 ## 11. 路由清单 当前保留的管理 API 路由: 1. `POST /admin/api/login` 2. `GET /admin/api/me` 3. `GET /admin/api/overview` 4. `POST /admin/api/debug/http` 5. `POST /admin/api/profile/redeem-codes` 6. `POST /admin/api/profile/redeem-codes/disable` `GET /admin` 已取消挂载,后续由独立后台前端工程承接页面入口。 ## 12. 完成定义 当前管理 API 保留与内嵌页面移除满足以下条件时,本任务视为完成: 1. `api-server` 内存在受保护后台管理域。 2. 管理员用户名密码可登录。 3. 普通用户 token 无法访问后台接口。 4. 后台能看到服务和数据库真实概览。 5. 后台能调试当前服务 HTTP 接口。 6. 兑换码管理 API 可由管理员 token 调用。 7. `GET /admin` 不再挂载,访问返回 `404`。 8. 独立后台前端 PRD 与技术方案已补齐。 9. 路由索引与技术文档已同步更新。