feat: complete unified plugin admin v1.1.0
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
|
||||
状态:Accepted Contract / V1 参考实现已完成本地验收
|
||||
|
||||
本文定义与 Sub2API Core 解耦的通用业务插件框架。业务插件是独立服务、独立端口、独立版本和独立 UI;它可以通过现有管理员自定义菜单嵌入 Core,也可以在新窗口运行。订阅管理只是一个可选业务插件,不能成为框架后台、Core 热路径或插件生命周期的固定组成部分。
|
||||
本文定义与 Sub2API Core 解耦的通用业务插件框架。业务插件的后端服务、端口和版本独立;浏览器端由统一的 Plugin Admin 控制面承载,业务插件 UI 以模块方式挂载到同一个管理员 Shell 中。订阅管理只是一个可选业务模块,不能成为框架后台、Core 热路径或插件生命周期的固定组成部分。
|
||||
|
||||
> **前端架构修订(2026-08-30)**:此前“独立 UI/独立管理员后台”的表述仅指后端服务可以独立部署,不表示业务模块要再次登录。Plugin Admin 负责唯一的管理员登录、会话、导航和 CSRF;订阅模块安装并启用后才出现在控制面导航中,继承同一会话,不提供第二个登录页或第二套 Cookie。
|
||||
|
||||
## 1. 目标
|
||||
|
||||
@@ -14,7 +16,7 @@ V1 需要提供一个独立的插件控制面,负责:
|
||||
- 保存插件版本、服务地址、运行状态、菜单声明和操作审计;
|
||||
- 通过 Core 现有管理员鉴权复用操作者身份;
|
||||
- 将已启用插件的管理员菜单注入 `custom_menu_items`;
|
||||
- 让每个业务插件仅通过自己的 BFF 调用 Core 明确允许的 API。
|
||||
- 让每个业务插件仅通过控制面或其受控模块 BFF 调用 Core 明确允许的 API。
|
||||
|
||||
V1 不改变 Core Go/Vue、数据库迁移、现有鉴权、前端路由或 `.s2plugin` transport ABI。控制面自己的注册表、安装目录、进程和配置存储属于独立服务;它不连接 Core PostgreSQL、Redis 或宿主业务表。
|
||||
|
||||
@@ -25,7 +27,7 @@ V1 不改变 Core Go/Vue、数据库迁移、现有鉴权、前端路由或 `.s2
|
||||
| 运行方式 | Core 子进程 + gRPC | 独立服务 + HTTP/BFF |
|
||||
| 能力 | `openai.oauth.outbound_transport.v1` | 由清单声明的业务能力 |
|
||||
| 生命周期 | Core `PluginManager` | 独立 Plugin Control Plane |
|
||||
| UI | 配置 iframe + UI Bridge | 业务后台/用户工具页面 |
|
||||
| UI | 配置 iframe + UI Bridge | 统一控制面中的业务模块页面 |
|
||||
| 数据边界 | Core 负责账号转发与计费 | Core 负责权威业务数据,插件只读/投影 |
|
||||
| 菜单 | Core 固定插件管理页 | `custom_menu_items` 管理员入口 |
|
||||
|
||||
@@ -60,7 +62,7 @@ Sub2API Core 现有鉴权、Admin API 和领域账本
|
||||
- `plugin_operator`:查看状态、日志摘要和健康诊断,不改变包或凭据。
|
||||
- `plugin_readonly`:只读查看已登记插件。
|
||||
|
||||
V1 的控制面只允许 Core `role=admin` 登录。插件不创建第二套 Core 用户表;插件会话只保存 `plugin_id`、`admin_user_id`、角色、会话版本和过期时间。UI 隐藏按钮不等于授权,控制面和 Core API 均须重新校验权限。
|
||||
V1 的 Plugin Admin 控制面只允许 Core `role=admin` 登录。插件不创建第二套 Core 用户表;控制面会话保存 `admin_user_id`、角色、会话版本和过期时间,订阅等业务模块直接继承该会话。模块不得创建自己的登录页、Cookie 或独立权限入口。UI 隐藏按钮不等于授权,控制面、模块后端和 Core API 均须重新校验权限。
|
||||
|
||||
## 5. 管理面契约
|
||||
|
||||
@@ -157,9 +159,16 @@ Core 返回 `401` 时,一次用户请求最多 refresh 一次;并发 refresh
|
||||
|
||||
## 9. 会话和嵌入
|
||||
|
||||
插件登录调用 Core 现有 `/auth/login`、按需 `/auth/login/2fa`,再调用 `/auth/me` 校验管理员角色。Core token 只存插件服务端会话,浏览器只持有 HttpOnly、Secure、SameSite Cookie 和插件 CSRF token。
|
||||
Plugin Admin 登录调用 Core 现有 `/auth/login`、按需 `/auth/login/2fa`,再调用 `/auth/me` 校验管理员角色。Core token 只存控制面服务端会话,浏览器只持有控制面的 HttpOnly、Secure、SameSite Cookie 和 CSRF token;订阅模块请求沿用这套会话。
|
||||
|
||||
Core 的自定义页面当前使用 sandbox iframe,且不会自动继承 Core `localStorage` 登录态。因此 V1 必须同时提供新窗口入口;iframe 首屏显示插件登录页是已知行为。真正无感 SSO 需要 V1.1 的一次性 code/state 或受控 `postMessage` 交接,不得把 JWT 放在 URL。
|
||||
会话和进程是两个独立的生命周期:插件作为常驻服务运行,Core access token
|
||||
到期时由后端按需 refresh,不要求重启插件。默认会话空闲 30 分钟、绝对上限
|
||||
8 小时;refresh 失败或 Core 撤销管理员后清除会话并要求重新登录。V1 会话
|
||||
默认只在插件进程内存中保存,所以控制面重启后需要重新登录一次,但已启用
|
||||
插件会按 registry 恢复。跨实例或跨重启免登录必须接入插件自有加密共享会话
|
||||
存储,不能把 Core token 放入浏览器或 Core 数据库。
|
||||
|
||||
Core 的自定义页面当前使用 sandbox iframe,且不会自动继承 Core `localStorage` 登录态。因此 iframe 首屏由 Plugin Admin 显示一次登录页;进入订阅模块时不再追加登录。真正无感 Core SSO 仍需要 V1.1 的一次性 code/state 或受控 `postMessage` 交接,不得把 JWT 放在 URL。
|
||||
|
||||
菜单注入使用 Core 现有 `custom_menu_items`:
|
||||
|
||||
@@ -167,7 +176,7 @@ Core 的自定义页面当前使用 sandbox iframe,且不会自动继承 Core
|
||||
{
|
||||
"id": "DOMAIN_PLUGIN_ID",
|
||||
"label": "DOMAIN_PLUGIN_LABEL",
|
||||
"url": "https://CORE_ORIGIN/extensions/DOMAIN_PLUGIN_ID/",
|
||||
"url": "https://PLUGIN_PUBLIC_ORIGIN/extensions/qiu.plugin-admin/admin/#/modules/DOMAIN_MODULE/overview",
|
||||
"visibility": "admin",
|
||||
"sort_order": 200
|
||||
}
|
||||
@@ -200,7 +209,7 @@ Core 始终是用户身份、余额、订阅、订单、用量、权限、计费
|
||||
|
||||
### Phase 2:业务插件适配
|
||||
|
||||
提供 `DOMAIN_PLUGIN_ID` 级别的 SDK/模板和契约测试。订阅管理作为首个独立业务插件接入,只实现自身领域页面和 Core 只读 API,不改变控制面。
|
||||
提供 `DOMAIN_PLUGIN_ID` 级别的 SDK/模板和契约测试。订阅管理作为首个业务模块接入统一控制面,只实现自身领域页面和 Core 只读 API,不复制控制面的登录、导航和会话。
|
||||
|
||||
### Phase 3:生产增强
|
||||
|
||||
|
||||
Reference in New Issue
Block a user