81 lines
4.1 KiB
Markdown
81 lines
4.1 KiB
Markdown
# 自定义菜单安全嵌入部署
|
||
|
||
## 背景
|
||
|
||
用户需要在 Sub2API 用户侧增加一级菜单,让用户点击后在站内看到第三方商铺页:
|
||
|
||
- 菜单名称:`购买套餐`
|
||
- 页面地址:`https://pay.ldxp.cn/shop/5HAP5JVN`
|
||
- 入口路径:`/custom/shop`
|
||
|
||
核心安全边界是第三方 iframe 不应收到 Sub2API 的用户 ID、登录 token 或来源 URL。
|
||
|
||
## 本次实现
|
||
|
||
- `custom_menu_items` 增加三态字段 `omit_auth_context`:
|
||
- `true`:安全嵌入,不追加 `user_id`、`token`、`src_host`、`src_url`。
|
||
- `false`:允许追加认证上下文,但只允许部署配置或环境变量声明的受信 origin。
|
||
- 缺省:兼容旧菜单;public/injection 输出时如果 URL 不受信,会收敛为 `true`。
|
||
- 新增菜单默认安全嵌入,后台 UI 增加“安全嵌入第三方页面”开关。
|
||
- 受信根只来自 `cfg.Server.FrontendURL` 和 `CUSTOM_MENU_AUTH_CONTEXT_TRUSTED_ORIGINS`,数据库/后台设置里的 `frontend_url` 不作为自授权信任根。
|
||
- 用户进入 `/custom/:id` 时强制刷新 public settings,降低信任策略撤销后的旧缓存风险。
|
||
- admin-only 自定义页面 fail closed:即使来自 admin settings,也不向 iframe 传 token。
|
||
- 侧边栏左上角不再渲染版本号。
|
||
|
||
## 线上部署
|
||
|
||
- 服务器:`个人-US-racknerd-0526-3c4g`
|
||
- IP:`216.45.59.243`
|
||
- 部署目录:`/opt/sub2api`
|
||
- 当前镜像:`sub2api:custom-menu-safe-embed-20260527-r2`
|
||
- 当前镜像 ID:`sha256:ceeea1a913ea8386f24b4296b856295c18febd0b19eeb1e92de4ef9512e3f3a2`
|
||
- 当前提交:`7954492cee99`
|
||
- 当前版本:`0.1.131`
|
||
- 上一版镜像:`sub2api:custom-menu-safe-embed-20260527`
|
||
- 镜像 ID:`sha256:356653e0e5a7b688faacb728a0f94d450e102393fd73bb16c705000f359133de`
|
||
- 部署方式:本地构建 linux/amd64 Go 二进制并嵌入前端,上传 runtime patch tar 到远程,在远程基于 `weishaw/sub2api:latest` 替换二进制和资源后 `docker commit` 生成本地镜像。
|
||
- runtime patch:`/tmp/sub2api-custom-menu-runtime-patch-20260527.tar.gz`
|
||
- runtime patch SHA256:`321b69bcf40470be9f2de10f8f1114ebd6bd7e6e014783b123c7160781ac127d`
|
||
- r2 runtime patch:`/tmp/sub2api-custom-menu-safe-embed-r2-runtime-patch.tar.gz`
|
||
- r2 runtime patch SHA256:`962de880c5e0917e3c6b351fd1955c3d94c8f7b6fcfae558492535c08faac0d0`
|
||
- 部署前备份:`/opt/sub2api/backups/deploy-custom-menu-20260526-222849`
|
||
- r2 部署前备份:`/opt/sub2api/backups/deploy-custom-menu-r2-20260527-000642`
|
||
- 菜单配置备份:`/opt/sub2api/backups/custom-menu-shop-20260526-224153`
|
||
|
||
## 线上菜单配置
|
||
|
||
远程 PostgreSQL `settings.custom_menu_items` 当前配置:
|
||
|
||
```json
|
||
[
|
||
{
|
||
"id": "shop",
|
||
"label": "购买套餐",
|
||
"icon_svg": "",
|
||
"url": "https://pay.ldxp.cn/shop/5HAP5JVN",
|
||
"visibility": "user",
|
||
"sort_order": 0,
|
||
"omit_auth_context": true
|
||
}
|
||
]
|
||
```
|
||
|
||
直接改数据库后需要重启 `sub2api` 容器或通过应用设置接口触发缓存刷新,否则 CSP 动态 `frame-src` 可能暂时不包含新 iframe origin。
|
||
|
||
## 验证记录
|
||
|
||
- `https://catproxy.lilifamily.com/api/v1/settings/public` 返回 `shop` 菜单项。
|
||
- `https://proxy.api.lilifamily.com/api/v1/settings/public` 返回 `shop` 菜单项。
|
||
- `https://catproxy.lilifamily.com/custom/shop` 返回 `200`。
|
||
- `https://proxy.api.lilifamily.com/custom/shop` 返回 `200`,响应头含 `X-Proxy-Ng-Node: jppro-akile-0504-1c1g`。
|
||
- `/custom/shop` 的 CSP `frame-src` 已包含 `https://pay.ldxp.cn`。
|
||
- `omit_auth_context=true` 时 iframe URL 不应包含 `token`、`user_id`、`src_host`、`src_url`。
|
||
- r2 远程二进制核对:`Sub2API 0.1.131 (commit: 7954492cee99, built: 2026-05-27T07:02:24Z)`。
|
||
- r2 公网 settings 核对:`proxy.api.lilifamily.com/api/v1/settings/public` 返回 `version=0.1.131`、`购买套餐`、`omit_auth_context=true`。
|
||
- r2 UI 变更:侧边栏左上角不再渲染版本号。
|
||
|
||
## 回滚
|
||
|
||
- 删除或清空 `settings.custom_menu_items` 中的 `shop` 项,并重启 `sub2api` 容器刷新 CSP 缓存。
|
||
- 或把 `/opt/sub2api/.env` 中 `SUB2API_IMAGE` 回退到部署前镜像,再执行 `docker compose up -d sub2api`。
|