Files
sub2api-add/docs/PLUGIN_FRAMEWORK_V1_RFC.md
T
Qiufeng 5feae3ad41
Business Plugins CI / check (plugin-admin) (push) Successful in 3m13s
Business Plugins CI / check (subscription-admin) (push) Successful in 1m41s
chore: initialize standalone business plugin repository
2026-08-27 23:36:08 +08:00

394 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sub2API 独立业务插件框架 V1 RFC
状态:V1 通用插件控制面参考实现已落库;订阅业务插件只读适配与 Core Host Adapter/写操作仍为 Draft
本文规划一种不改动 Sub2API 核心代码、数据库和现有插件 ABI 的独立业务插件框架。当前 V1 控制面参考实现位于 `plugins/plugin-admin`,它负责插件清单、签名、安装、启停、升级、回滚、卸载、配置、审计和菜单注入;控制面本身不是订阅后台。每个业务插件(包括独立的 `plugins/subscription-admin`)作为可选的独立服务运行在自己的端口,通过控制面安装后再由部署层反向代理和现有“管理员可见自定义菜单”嵌入 Sub2API 页面。插件登录直接调用 Core 的现有鉴权,普通账号没有访问权限,也不复制 Core 用户表。
V1 已实现范围以 `plugins/plugin-admin` 控制面和本文“当前实现范围”章节为准;本文中的订阅业务插件只是首个适配样例。Core Host Adapter、短时 Plugin Access Token、无感 SSO 和余额写操作仍是后续版本设计,不代表当前 Core 已提供这些接口。
本文不是现有 `.s2plugin` 协议的直接改版。现有 `.s2plugin` 继续只负责 `openai.oauth.outbound_transport.v1`。本 RFC 的 V1 是部署级业务插件约定,不向当前 Core 增加新的路由、数据表或业务 RPC。
## 0. 约束与可行性边界
本版本必须同时满足以下约束:
- 不修改 Sub2API 的 Go、Vue、数据库迁移和现有鉴权实现;
- 不在插件内建立 Core 用户表,管理员身份以 Core 现有账号和角色为准;
- 插件后端独立监听 `PLUGIN_PORT`,由 Nginx/Caddy/Traefik 等部署层转发;
- 通过 Core 已有 `custom_menu_items` 配置添加 `visibility=admin` 的 iframe 菜单入口;
- 插件只在服务端调用 Core 现有 API,浏览器不持有 `x-api-key` 或 Core JWT;
- 第一阶段只搭框架、登录、权限、健康检查、嵌入和只读联调,不实现订阅购买写操作。
现有自定义菜单可以完成“把插件页面显示在 Sub2API 管理页面内”,但现有 iframe 使用 sandbox,且 Core 前端 JWT 保存在 `localStorage`,不会自动注入跨端口 iframe。因此在完全不改 Core 的前提下,V1 的登录方式是:插件登录页把凭据转交给插件后端,插件后端调用 Core 现有登录和二次验证接口,确认 `role=admin` 后只保留短时插件会话及服务端 Core token;这复用同一套 Core 用户和角色,不复制用户表,但不是无感知的当前页面会话共享。
如果以后要求“已登录 Core 后打开 iframe 立即无感登录”,需要一个很小的 Core 一次性登录交接接口或前端 `postMessage` 适配;这属于 V1.1,不应通过 URL 明文传递 JWT。反向代理只改变网络路径,不改变这一认证边界。
## 1. 决策摘要
### 1.1 推荐拓扑
```text
管理员浏览器
│ Core 页面中的 admin 自定义菜单
▼
Core `/custom/PLUGIN_ID`
│ 现有 sandbox iframe;只加载插件 UI,不共享 Core 存储
▼
反向代理 `/extensions/PLUGIN_ID/*`
│ 转发到独立服务 `127.0.0.1:PLUGIN_PORT`
▼
业务插件后台
├─ `/login` 接收管理员登录请求
├─ 服务端调用 Core `/api/v1/auth/login`(需要时调用 `/login/2fa`)
├─ 调用 Core `/api/v1/auth/me`,确认 `role=admin`
├─ 建立插件 HttpOnly 会话,Core access/refresh token 只在服务端保存
└─ 通过 Bearer Core JWT 调用现有 Core Admin API
▼
Sub2API Core 现有认证、Admin API 和订阅/余额账本
```
插件后台是独立服务,不以高权限子进程形式嵌入核心,也不直接连接核心数据库。V1 通过部署层完成端口映射,通过 Core 现有登录/2FA、`/auth/me` 和 Admin API 完成功能联调;浏览器永远不接触 Admin Key,也不接触 Core JWT。插件后端不建立用户表,只维护短期会话(单实例可使用内存,多实例可使用插件自己的 Redis/会话存储)。这里的前提是插件属于受信任的内部服务:登录密码会在一次请求中经过插件后端再转交 Core,但不落库、不写日志;若要求插件进程也完全接触不到密码,需要另行引入 Core SSO/OIDC。
如果部署环境只允许服务到服务调用,也可以把 Core Admin API Key 放在插件后端 secret 中作为临时 BFF 凭据;这时所有命令都以该 Key 对应的管理员身份执行,属于单一服务身份模式,不等同于当前浏览器管理员的 SSO,也不替代 V1 的管理员登录方案。
### 1.2 V1 的默认范围
- 插件拥有独立后台和独立发布版本。
- 只允许管理员登录;普通用户访问插件后台一律拒绝。
- 首版支持管理员登录、权限校验、健康检查、嵌入和只读订阅数据展示。
- 余额购买命令暂不实现,待框架验收后再复用现有订阅逻辑设计原子入口。
- 现有 `.s2plugin` 传输插件 ABI、路由和生命周期保持不变。
- 不实现插件任意注册核心路由、任意执行 SQL、任意读取宿主 Cookie、任意注入 Vue 路由或任意修改 Core 菜单组件。
## 2. 为什么不复用现有 `.s2plugin`
现有插件协议的能力是 `GetInfo`、`Health`、配置读写、配置测试和 `Forward` HTTP 流。它的清单只接受 `openai.oauth.outbound_transport.v1`,UI 也只是无管理员 Token 的配置 iframe。
因此它不适合安全承载以下业务:
- 管理员登录和角色授权;
- 订阅商品、余额购买和订单审计;
- 核心数据库事务或迁移;
- 用户页面、菜单、任意 HTTP 路由和支付/订阅回调。
如果把这些能力硬塞入现有协议,就会同时改变进程 ABI、权限模型、数据库边界和前端路由,反而扩大与上游的冲突面。V1 采用“外部业务插件 + Core 现有 API 适配器”作为清晰的新边界;需要 Core 新增接口的部分另列为 V1.1。
## 3. 术语和边界
| 术语 | 定义 |
|---|---|
| Core | Sub2API 主服务,拥有用户、余额、Group、Key、订阅和用量账本。 |
| Business Plugin | 独立部署的后台服务,提供一个业务域的管理 UI 和 BFF。 |
| Plugin UI | 由 Business Plugin 提供的页面,只调用自己的后端。 |
| Plugin Backend | Business Plugin 的服务端,保存插件配置、会话和操作幂等记录。 |
| Core API Adapter | V1 插件后端对 Core 现有 REST API 的服务端客户端,只允许访问明确的认证、管理员和只读业务端点。 |
| Future Host Adapter | V1.1 以后、需要修改 Core 才能提供的版本化业务 API;不属于本次无 Core 改动的实现范围。 |
| Plugin Session Credential | 插件自己的 HttpOnly 会话标识,不等于 Core JWT 或全局 Admin Key。 |
| Capability | 插件声明的业务能力,例如 `subscription.admin.v1`。 |
| Projection | 插件保存的只读或可重建副本,不是核心账本的权威数据。 |
## 4. 认证与权限模型
### 4.1 管理员登录
V1 采用“插件会话 + Core 现有登录”的两层模型,不创建插件用户表:
1. 浏览器打开插件 `/login`,只向插件后端提交 Core 管理员凭据和必要的 2FA 信息。
2. 插件后端服务端调用 Core `POST /api/v1/auth/login`;需要二次验证时继续调用 `POST /api/v1/auth/login/2fa`。
3. 插件后端用返回的 Core access token 调用 `GET /api/v1/auth/me`,确认用户状态正常且 `role=admin`。
4. 插件后端建立自己的短时 HttpOnly 会话;Core access/refresh token 只保存在插件服务端的会话存储中,不回传浏览器。
5. 插件业务请求只携带插件会话 Cookie,插件后端再用对应管理员的 Core Bearer token 调用允许的 Core API。
```text
浏览器 -> Plugin /login(插件会话 Cookie 尚未建立)
Plugin -> Core /api/v1/auth/login
Plugin -> Core /api/v1/auth/login/2fa(按 Core 返回的要求)
Plugin -> Core /api/v1/auth/me(确认 role=admin)
Plugin <- 建立 HttpOnly 插件会话
浏览器 -> Plugin /admin/*(只带插件会话 Cookie)
Plugin -> Core /api/v1/admin/*(只在服务端带 Bearer Core JWT)
```
这不是独立账号,也不是把 Core 用户复制到插件;密码只用于一次 Core 登录请求,插件不落库。插件会话可使用内存存储;多实例部署时使用插件自己的 Redis/会话存储,不连接 Core 数据库。Core 继续负责密码、2FA、限流、TokenVersion、撤销和管理员角色校验。
当前 Core 没有给自定义 iframe 提供 token handoff,因此“Core 已登录后打开 iframe 自动登录”不属于 V1。V1 允许在 iframe 内显示插件登录页;由于 sandbox/第三方 Cookie 策略可能让嵌入会话在刷新后失效,插件必须提供“新窗口打开插件”入口作为稳定登录路径。以后如需真正无感 SSO,另行设计一次性 code + state 或 `postMessage` 交接机制,JWT 不应放在 URL。
### 4.2 权限判定
- 默认拒绝所有普通用户、未登录用户和过期会话。
- 插件会话只包含 `plugin_id`、`admin_user_id`、角色、权限版本、签发时间和过期时间。
- V1 只定义 `plugin_admin` 角色;后续可增加 `subscription_operator`、`subscription_readonly`。
- 插件后端每次命令都携带对应 Core 管理员的 Bearer token,不使用“系统管理员”固定身份代替实际操作者(仅使用临时 Admin Key 的过渡模式除外)。
- Core 对每个现有 Admin API 操作再次做管理员角色、会话撤销和资源级授权,不把插件 UI 的按钮隐藏当作授权依据。
- 所有写操作要求 CSRF 防护、审计记录和幂等键;敏感操作可要求 step-up。
### 4.3 会话要求
- 会话 Cookie 必须 `HttpOnly`、`Secure`、`SameSite=Lax` 或更严格。
- 生产环境只允许 HTTPS;反向代理必须正确传递原始 Host 和协议。
- 登录使用短时一次性 state,绑定浏览器会话并防重放。
- 默认会话有效期 30 分钟,滑动续期上限 8 小时;登出立即撤销服务端会话。
- 独立 origin 嵌入时按浏览器策略使用 `SameSite=None; Secure`,同源反代优先使用 `Lax`;必须在目标浏览器验证刷新、退出和第三方 Cookie 行为。
- 插件 UI 不把 Core JWT、Admin Key 或服务凭据写入 LocalStorage、URL、HTML、日志或错误提示。
## 5. Admin Key 与服务凭据安全
### 5.1 绝对禁止的做法
- 不把全局 `x-api-key` 注入浏览器。
- 不把 Admin Key 放进插件静态 JS、HTML、iframe、URL query、下载文件或前端 sourcemap。
- 不让插件 UI 直接请求 Core Admin API。
- 不把 Admin Key 写入普通业务日志、请求追踪、错误响应、数据库明文或备份导出。
- 不让插件直接连接 Core PostgreSQL、Redis 或宿主文件目录。
### 5.2 V1 凭据分级
| 环境 | 凭据 | 用途 | 约束 |
|---|---|---|---|
| 开发 | Core 管理员的临时登录凭据 | 调用 Core `/auth/login` 联调 | 只由开发者输入到插件登录页,不写入代码、配置和日志。 |
| 测试 | Core 返回的 access/refresh token | 建立插件服务端会话 | 只存插件服务端会话存储,短 TTL,测试 Core 与测试管理员专用。 |
| 生产 | Core 返回的 access/refresh token | 代表实际登录的 Core 管理员调用现有 Admin API | 服务端加密保存或内存保存,按 Core TokenVersion/撤销结果失效;不回传浏览器。 |
V1 不要求新增 Plugin Access Token 服务,也不要求修改 Core。`ADMIN_API_KEY` 只作为服务到服务 BFF 的应急/测试凭据:它必须只存在插件后端 secret manager、受限环境变量或权限为 `0600` 的 secret 文件中,并由 Core Admin API 的 endpoint allowlist 限制。使用 Admin Key 时所有请求都以同一个管理员身份执行,审计粒度是服务身份级别,不得作为插件登录态下发给浏览器。
V1.1 如需在不保存 Core refresh token 的情况下运行,再设计 Core 签发的短时、限 scope Plugin Access Token;在 Core 提供该能力前,文档只把它视为未来接口。
### 5.3 凭据生命周期
1. 插件后端接收管理员登录请求,但不保存密码。
2. 插件后端调用 Core 登录/2FA,保存返回 token 到服务端会话,并绑定 `admin_user_id`。
3. 每次 Core 请求都使用 TLS 和 Core Bearer token;Core 继续校验签名、TokenVersion、会话绑定和角色。
4. access token 过期时只使用对应 refresh token 调用 Core `/auth/refresh`;刷新失败就销毁插件会话并要求重新登录。
5. 登出、Core 管理员撤销会话、停用插件或发现泄露时,立即删除插件会话;Admin Key 过渡模式由运维轮换并撤销。
### 5.4 服务端防护
- Core 现有 Admin API 由自身 `adminAuth`、JWT 会话和管理员角色保护;插件后端再使用出站 allowlist,只能访问事先批准的 Core API 路径。
- 插件后端不接受任意 URL 转发,也不把 Core API 代理能力暴露给插件 UI。
- 请求设置超时、重试上限和熔断;禁止在超时后盲目重放非幂等命令。
- 日志对 `Authorization`、`x-api-key`、Cookie、session、余额和个人信息做结构化脱敏。
- 记录 `plugin_id`、操作者、scope、资源 ID、幂等键和结果,不记录 secret 原文。
- 生产插件运行在独立低权限账号或容器中,限制文件、网络、系统调用和环境变量。
## 6. Core API Adapter V1(使用现有接口)
本节描述在“不修改 Sub2API”前提下插件可以使用的最小集成面。它不是 Core 已注册的插件协议,而是插件后端对现有 HTTP API 的严格 allowlist;实现前应根据目标版本在插件配置中冻结路径和响应字段。
### 6.1 认证头
```http
Authorization: Bearer CORE_ACCESS_TOKEN
X-Request-Id: UNIQUE_REQUEST_ID
```
`CORE_ACCESS_TOKEN` 只允许由插件后端的会话适配器发送。插件浏览器、静态资源和 iframe 消息中不得出现该 token。
### 6.2 V1 允许的接口类别
```text
POST /api/v1/auth/login
POST /api/v1/auth/login/2fa
POST /api/v1/auth/refresh
POST /api/v1/auth/logout
GET /api/v1/auth/me
GET /api/v1/settings/public
GET /api/v1/admin/payment/plans
GET /api/v1/admin/subscriptions
GET /api/v1/admin/subscriptions/{id}
GET /api/v1/admin/users/{id}
GET /api/v1/admin/users/{id}/subscriptions
```
实际插件先只开放只读管理员接口;不得把路径中的 `<read-only-endpoint>` 当作通配符,部署配置必须列出具体路径、方法和分页上限。现有 Core 没有 `/api/v1/plugin-host/*` 路由,V1 不调用或宣称该路径已存在。
### 6.3 V1 写操作边界
V1 框架和第一版订阅插件不实现余额扣款、订阅续期或撤销写操作。现有 Admin API 的多个调用不应拼成一笔购买,因为这样无法保证余额、订单、订阅和审计的单事务一致性。
未来要支持写操作,必须先在 Core 中增加版本化 Host Adapter 或等价的原子命令接口(需要 Core 代码、路由、审计和幂等存储变更),再由插件接入;这属于 V1.1,不是本轮“零 Core 改动”的交付物。
### 6.4 错误和重试
| HTTP | 含义 | 插件行为 |
|---|---|---|
| `401` | 凭据无效或已撤销 | 停止重试,提示重新注册/轮换。 |
| `403` | 管理员角色、会话或资源权限不足 | 不重试,记录操作者和资源。 |
| `409` | 幂等键冲突或业务状态冲突 | 查询 operation 状态后展示最终结果。 |
| `422` | 参数或余额业务校验失败 | 展示可读错误,不重试。 |
| `429` | Core 限流 | 按 `Retry-After` 有上限地重试。 |
| `5xx` | Core 暂时故障 | 只对明确幂等命令重试,指数退避。 |
## 7. 插件注册、清单与生命周期
### 7.1 与 `.s2plugin` 分离
Business Plugin V1 不直接套用现有 `manifest.schema.json`。建议新增独立的业务插件清单,例如 `business-plugin-manifest.v1.json`:
```json
{
"schema_version": 1,
"plugin_id": "example.subscription",
"name": "Example Subscription Admin",
"version": "0.1.0",
"core_api_baseline": "sub2api-0.1.183",
"capabilities": ["subscription.admin.v1"],
"tested_core_versions": ["0.1.183"],
"backend": { "health_path": "/healthz" },
"ui": { "entrypoint": "/admin" },
"publisher": { "key_id": "publisher-key-id" }
}
```
清单只声明能力和兼容范围,不授予数据库、路由或 secret 权限。V1 由部署脚本/反向代理保存清单、校验签名和允许的 Core API 路径;当前 Core 不会读取该清单,也没有业务插件注册表。插件发布包/容器镜像仍应签名,但签名验证属于部署门禁,不应写成现有 Core 能力。
### 7.2 状态机
```text
registered -> disabled -> enabled -> draining -> disabled
│ │ │
└────── incompatible └── error
```
- `registered`:部署层已登记清单和发布者,但未启用。
- `disabled`:服务存在但不接收业务请求。
- `enabled`:健康检查通过,允许插件后端调用列入 allowlist 的 Core API。
- `draining`:停止接收新命令,等待进行中的幂等命令完成。
- `error`:健康检查或 Core API 合约校验失败,默认 fail-closed。
- `incompatible`:插件清单或 Core API 版本不兼容,不允许启用。
### 7.3 升级和回滚
- 插件版本独立于 `backend/cmd/server/VERSION` 和 `frontend/package.json`。
- 升级前先执行健康检查、现有 Core API contract test 和插件自身数据备份检查。
- 新版本不兼容时保持旧版本运行,不自动覆盖正在启用的实例。
- 停用时等待进行中的命令完成;超过 drain 超时则拒绝新命令并标记待恢复。
- 插件卸载不删除 Core 订阅、余额和审计数据。
## 8. 数据归属
### 8.1 Core 权威数据
- 用户身份和管理员授权;
- 余额账本;
- 套餐价格、额度、覆盖 Group 和购买快照;
- 用户订阅状态、期限、配额和 reserved;
- 余额扣减、订阅创建/续期、撤销和审计;
- 请求计费、额度预留、结算和幂等。
### 8.2 Plugin 可拥有的数据
- 插件管理员会话和本地角色映射;
- 插件 UI 偏好、筛选条件和缓存;
- Core API operation 的本地查询索引;
- 供应商或业务侧的非权威展示配置。
插件数据库中的订阅副本必须可删除、可重建、带来源版本和更新时间。它不作为网关放行请求的依据。
## 9. 前端和菜单集成
V1 通过现有的管理员自定义菜单嵌入,不修改 Core 前端路由:
```text
Core 设置 -> custom_menu_items
id: example.subscription
visibility: admin
url: https://PLUGIN_ORIGIN/extensions/example.subscription/
Core `/custom/example.subscription`
└── sandbox iframe -> 反向代理 -> `127.0.0.1:PLUGIN_PORT`
```
`visibility=admin` 只负责隐藏普通账号的菜单入口,插件后端仍必须独立鉴权。现有 iframe 的 sandbox、跨端口 origin 和 Core JWT `localStorage` 使其不会自动共享 Core 登录态;因此 iframe 首屏显示插件登录页是 V1 的预期行为。插件也应提供“新窗口打开”,便于登录后保持自身会话。
生产部署建议把插件外部地址挂在与 Core 相同的 HTTPS 站点下,由 Nginx/Caddy 按路径反代到独立端口;这只减少浏览器跨域问题,不改变插件必须登录和服务端调用 Core 的事实。若使用独立 origin,必须在 Core CORS 中精确加入该 origin,禁止 `*`,并仅允许必要的 `Authorization` 请求头。
插件页面只调用自己的 `/plugin-api/*`,由插件后端调用 Core 现有认证和管理员 API。V1 不允许插件动态注入主应用 Vue 路由、修改核心菜单组件或覆盖全局 CSS;主应用只提供一个受权限控制的“业务插件”入口,插件内部菜单由插件自己管理。
## 10. 威胁模型与处置
| 威胁 | V1 处置 |
|---|---|
| XSS 窃取 Admin Key | 浏览器永远没有 Admin Key;Cookie HttpOnly;CSP 和输出编码。 |
| 插件前端伪造管理员命令 | 插件后端重新验证插件会话;Core 重新验证 Bearer token、管理员角色、操作者和资源权限。 |
| 插件后端日志泄露 secret | 统一日志脱敏,禁止记录 Authorization 和完整请求。 |
| 插件服务被攻破 | 限制 Token scope、TTL、出站地址和 Core API;立即撤销凭据。 |
| 重放余额购买 | Idempotency-Key + Core 事务记录 + 请求时间/nonce。 |
| CSRF | SameSite Cookie、CSRF token、Origin/Referer 校验。 |
| SSRF | 插件出站 allowlist;Core 现有 API 不接受任意 URL。 |
| 普通用户进入后台 | 插件登录调用 Core `/auth/me` 并要求 `role=admin`;所有插件路由默认 deny。 |
| 多实例状态漂移 | Core 是权威;插件状态通过健康检查和配置版本对齐。 |
| 插件卸载误删订阅 | 插件没有删除 Core 账本的权限,卸载只撤销凭据。 |
必须明确:独立插件进程不是操作系统级沙箱,签名只证明发布者和完整性,不证明代码无漏洞。生产部署仍需要低权限运行、网络隔离和可撤销凭据。
## 11. 测试门禁
### 11.1 Core API Adapter 合约测试
- Core 登录、`/login/2fa`、`/auth/me`、access/refresh 过期和撤销;
- 普通用户、停用用户、无效会话和跨插件会话均返回 `403`;
- 只读 Admin API 的字段脱敏、分页上限和资源权限;
- Core 超时、`401/403/429/5xx`、刷新 token 和重新登录;
- V1 明确没有 `/api/v1/plugin-host/*`,测试不能把未来接口当成现有接口。
### 11.2 插件后端测试
- Core 登录代理、2FA、会话过期、登出和 CSRF;
- Core access/refresh token 不进入响应、页面、日志和异常堆栈;
- Core `401/403/429/5xx` 的处理和刷新失败后的重新登录;
- 只允许配置中列出的 Core API endpoint;
- 插件服务重启后会话失效或从插件自己的会话存储恢复,不能依赖 Core 用户表。
### 11.3 浏览器和部署测试
- 管理员可登录,普通用户无法登录或访问任何后台 API;
- 不同屏幕下页面无横向泄露和敏感字段;
- 浏览器 DevTools 的请求、下载和页面源中没有 Admin Key;
- HTTPS、反向代理、容器低权限、secret 文件权限和日志脱敏;
- 停用、升级、回滚、凭据撤销后所有写操作按预期失败。
## 12. 分阶段实施计划(不含本次代码)
### Phase 0:冻结部署契约
- 选择外部服务部署方式(推荐同源反向代理 + 独立服务);
- 冻结插件端口、反向代理路径、`custom_menu_items` 字段和健康检查;
- 冻结允许调用的现有 Core API 路径、字段、分页和错误处理;
- 明确插件登录通过 Core `/auth/login`/`/login/2fa`,不创建用户表;
- 建立 Core token 会话销毁、Admin Key 过渡和日志脱敏方案。
### Phase 1:框架最小实现
- 独立服务目录、清单、发布者签名和部署兼容性检查;
- Plugin Backend 管理员登录和会话;
- Core access/refresh token 服务端会话适配器;
- 插件健康检查、启停、操作审计和同源入口;
- Core API allowlist、contract test 与本地示例插件。
### Phase 2:订阅插件试验
- 只读套餐、用户余额和订阅列表;
- 管理员操作页面、查询缓存和审计;
- 使用测试 Core 和测试账户,不连接生产余额;
- 余额购买、续费和撤销暂不实现,等待 Core 原子接口冻结。
### Phase 3:生产准备
- 未来 Core Host Adapter/短时 Plugin Access Token(若确认需要 Core 改动);
- step-up、密钥轮换和撤销;
- 多实例、备份恢复、升级回滚和故障演练;
- 通过安全、契约、浏览器和并发门禁后再启用。
## 13. 待确认事项
以下事项在写代码前必须确定:
1. V1 的订阅插件只允许管理员操作;普通用户购买页不纳入本框架首版。
2. 管理员登录是否按本文通过 Core `/auth/login` 和 `/login/2fa` 完成;确认不创建插件用户表。
3. 插件采用独立服务端口 + 同源反向代理,还是独立 origin;需确定生产网络拓扑。
4. V1 是否允许测试环境使用服务端专用 Admin Key;生产默认不使用,除非接受单一管理员审计语义。
5. 插件是否允许保存只读缓存;无论选择何种缓存,Core 必须始终是权威来源。
6. V1.1 是否需要真正无感 SSO 和 Core Host Adapter;若需要,单独立项修改 Core。
在这些问题确认前,不应开始实现插件协议、数据库表或前端页面。