Appearance
Agents 接入(自助配对与数据 API)
让外部 Agent 通过「owner 确认式自助配对」获得一个有作用域限制的只读数据 API 通道。
Ghome 管理后台为外部 Agent(如自研 Agent、第三方助手)提供一条受控接入通道:Agent 拿到一枚短期配对码,由应用 owner 登录后台确认后,换取一个带 Bearer token 和作用域(scope)的凭证,之后即可调用 /api/agent/v1/** 的数据 API。整套设计的出发点是不信任互联网、最小权限、可审计。
核心概念
| 概念 | 含义 |
|---|---|
| Agent Client | 一个已授权的 Agent,持有唯一 Bearer token 和一组 scope,可启用/禁用、可设过期。 |
| 配对码(Pairing Code) | 一次性、30 分钟有效的 8 位短码,是人工配对的中介凭证。 |
| 自助配对(Self-Pairing) | Agent 自行读取公开引导页取得配对码,再交由 owner 确认。 |
| Owner 确认 | 配对必须由登录态管理员在后台完成,不是免鉴权自助兑换。 |
| Scope | 端点级权限,如 content:published、analytics:read、ops:contacts。 |
数据模型
四张表(Prisma / PostgreSQL):
agent_clients—— Agent 凭证。关键字段:tokenPrefix(可读前缀)+tokenHash(sha256(token),原始 token 永不入库)、scopes[]、disabled、expiresAt、lastUsedAt、origin(admin直建 /self-paired配对)、createdByAdminId。agent_access_log—— 访问审计。endpoint、status(ok/denied)、ts。agent_pairing_codes—— 配对码。仅存codeHash = sha256(码)+ 与码无关的随机工单号codePrefix;usedAt标记焚码,usedByAgentClientId回填兑换出的 client。agent_pairing_config—— 单行开关表(id = 'singleton'),enabled控制公开配对通道,出厂默认false。
为什么只存哈希
原始 token 与原始配对码都不落库,只保存 sha256 哈希。库被读到也无法反推出可用凭证;原始值仅在创建那一刻一次性展示给 owner。
自助配对流程
text
① 管理员在后台开启「公开配对通道」 → agent_pairing_config.enabled = true(写审计)
② Agent 读取公开引导页 GET /agent/pair.md → 通道开则铸一枚 8 位短码 + 步骤指引(免鉴权)
③ Agent 把短码交给 owner
④ Owner 登录后台 → 「Agent 接入」引导卡第③步输入短码(+ 可选名称)
⑤ 后台校验:通道开启? 码存在? 未使用? 未过期?
→ 事务内原子焚码(updateMany where usedAt=null)防并发双花
→ 生成 token、建 AgentClient(scope 固定 content:published、origin=self-paired)
→ 写审计 agentClient.pair
⑥ 跳转编辑页一次性展示 Bearer token(关闭后库内仅哈希,不再可见)
⑦ Owner 把 token 配进 Agent,之后携 Authorization: Bearer <token> 调数据 API配对码状态机:
text
已铸码(expiresAt = now + 30min)
├─ 已用(usedAt 置位 + 回填 client) → 审计
├─ 已过期(expiresAt < now) → 拒绝
└─ 未用且未过期 → 可确认安全默认
自助配对出的 client 固定只有 content:published 权限。更高权限(analytics、ops)只能由管理员事后在编辑页手工勾选提权,并留审计——避免公开通道直接放出敏感数据访问权。
数据 API
认证:请求头 Authorization: Bearer <token>。后台用 sha256(token) 反查 agent_clients,校验 disabled、expiresAt 后放行。
个性化 Skill.md:GET /api/agent/v1/skill.md 会只列出该 client scope 内可用的端点,作为 Agent 的自描述接入说明。
端点分组(共 20+ 条,均在 /api/agent/v1/ 前缀下):
| 分组 | 所需 scope | 代表端点 |
|---|---|---|
| 内容(读) | content:published | /apps、/videos、/guides、/topics、/albums、/rankings、/categories、/tags(列表分页,详情按 :slug) |
| 内容(写) | content:write | POST /apps、POST /videos … 创建并发布 |
| 分析 | analytics:read | /analytics/clicks/daily、/analytics/redirects/top |
| 运营 | ops:* | /redirects、/audit-log、/contact-submissions、/admins |
状态门控:无 content:all 时强制 status=published,?status=draft 被静默忽略(防越权探测);有 content:all 时可查 draft/archived/all。
响应约定:列表统一信封 { data, page, pageSize, total }(pageSize ≤ 100),详情直接返回对象,错误返回 { error: "..." }。
错误码:401 unauthorized / token_revoked / token_expired、403 forbidden(scope 不足)、404 not_found、400 invalid_request。
后台管理界面
- 列表页
/agent-clients—— 顶部三态引导卡(通道未开 / 已开无 Agent / 已开有 Agent),含可复制的接入话术、内联输码表单、pairError中文错误透出;下方是 Agent 列表(名称 / 来源 / token 前缀 / scopes / 状态 / 最近使用 / 过期)。 - 编辑页
/agent-clients/[id]/edit—— 一次性 token 展示条、scope 多选、启用/禁用、过期、备注,以及轮换 token、吊销、更新操作,全部走审计。 - 配对码日志
/agent-clients/pairing-codes—— 只读表格,不显示原始码,仅展示创建/过期时间、状态、确认管理员、兑换出的 client。
安全设计要点
| 威胁 | 防护 |
|---|---|
| 原始 token 泄露 | 仅哈希入库,原始值一次性展示 |
| 配对码被猜 | 需登录态管理员确认 + 8 位短码 + 30min TTL + 原子焚码 |
| 权限越界 | manifest 驱动的 scope 校验 + content:all 状态门控 |
| 敏感数据泄露 | contact-submissions、admins 等仅在显式 ops scope 下可达 |
| 并发双花 | 事务内 updateMany(where usedAt=null) 原子检测 |
| 吊销/过期滞后 | 每次请求即时检查 disabled 与 expiresAt,无缓存 |
三层结构性兜底:公开通道默认关(管理员显式开启)→ 配对码一次性 + 短 TTL + 原子焚码 → 配对出的 client 固定最小 scope + 全链路审计(origin / createdByAdminId / agentClient.pair)。
关键实现位置
源项目:
ghome(pnpm monorepo)。以下为仓库相对路径。
- 数据模型:
packages/db/prisma/schema.prisma;迁移20260518000000_agent_clients、20260518100000_agent_self_pairing - Agent API 库:
apps/admin/lib/agent-api/(token.ts令牌、pairing.ts短码、scopes.ts作用域、manifest.ts端点表、auth.ts鉴权、queries.ts查询、skill-md.ts自描述文档) - 配对 DB 层:
apps/admin/lib/agent-pairing-db.ts、apps/admin/lib/agent-clients-db.ts - API 路由:
apps/admin/app/api/agent/v1/[[...slug]]/route.ts、公开引导apps/admin/app/agent/pair.md/route.ts - 后台 UI:
apps/admin/app/(admin)/agent-clients/(page.tsx、[id]/edit/page.tsx、pairing-codes/page.tsx、actions.ts) - 设计文档:
docs/superpowers/specs/2026-05-18-admin-agent-data-api-design.md、2026-05-18-agent-self-pairing-design.md、2026-06-10-agent-onboarding-card-redesign-design.md