From 6ca609fde44edefced788311ba2b32ab2ee2565e Mon Sep 17 00:00:00 2001 From: opsx Date: Thu, 22 Oct 2026 09:00:11 +0800 Subject: [PATCH] Suggest configured HTTPS domain for OpenVPN OIDC entry --- docs/specs/SDD-006-oidc-domain-suggestion.md | 40 ++++++++++++++++++++ frontend/src/components/OpenVPNOIDCGuide.vue | 13 ++++++- frontend/src/locales/en-US.json | 5 ++- frontend/src/locales/zh-CN.json | 5 ++- 4 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 docs/specs/SDD-006-oidc-domain-suggestion.md diff --git a/docs/specs/SDD-006-oidc-domain-suggestion.md b/docs/specs/SDD-006-oidc-domain-suggestion.md new file mode 100644 index 0000000..49d0fe2 --- /dev/null +++ b/docs/specs/SDD-006-oidc-domain-suggestion.md @@ -0,0 +1,40 @@ +# SDD-006:复用公网域名填写认证入口 + +| 字段 | 内容 | +|---|---| +| 版本 / 级别 | 0.1 / S2 | +| 设计状态 | 已确定 | +| 实现状态 | 已实现,前端构建通过;线上交互待验证 | +| 日期 | 2026-10-22 | +| 关联需求 | 创建 OpenVPN OIDC 专线时自动引用已有 HTTPS 公网域名 | + +## 1. 背景、目标与范围 + +`OpenVPNOIDCGuide.vue` 当前要求手填 `oidc_base_url`,已有 `GET /api/tunnels/openvpn/oidc-readiness` 返回 `management_domain` 和 `https_management_ready`。减少重复输入:仅在 HTTPS 已就绪、创建专线且字段为空时填入 `https://`;编辑既有专线及管理员手动地址不覆盖。此变更不提供 OIDC issuer,也不更改 Nginx 转发规则。 + +## 2. 需求与约束 + +- FR-01:已有 HTTPS 管理入口时,创建向导自动填写认证入口根地址;编辑保持原配置。 +- FR-02:无有效 HTTPS 域名或旧后端不提供就绪信息时仍允许手动填写;用户手动更改后不覆盖。 +- NFR-01:显示清晰的状态,说明自动填写只是地址建议,现有管理 Nginx 尚未代理 OAuth2 路径,需先配置认证组件的 HTTPS 路由;不可显示为已连通。 +- NFR-02:发行者、Client ID/Secret 仍须来自实际 OIDC 提供方,不以管理域名推断 issuer。 + +## 3. 架构与契约 + +前端复用 readiness 的现有管理域名和 TLS 就绪字段,不增加服务端接口、数据字段或迁移;OIDC 配置仍存储实际字符串,不对其添加动态绑定语义。证书域名变化时已创建的专线需要管理员核对并更新回调配置。 + +## 4. 风险与验收 + +已签发管理证书不意味着 `/oauth2/callback` 已可达;页面持续显示未配置认证入口的告警,填充不代表可用。每条 OIDC 专线要求唯一入口,复用同域名仅适用于第一条;后续专线保持手动输入独立域名,已有后端冲突校验兜底。 + +| 验收 | 预期 | +|---|---| +| 新建且 HTTPS 已就绪 | 空地址自动填当前域名、显示“仅填写地址”的告警 | +| 编辑或已输入独立域名 | 不覆盖原值 | +| 无 HTTPS 或旧服务端 | 保持空地址并可手动编辑 | +| 发行者 | 不自动填写,不把管理站点误标成 OIDC issuer | +| 检查 | 前端构建和后端相关单元测试通过;真实飞书/OIDC 登录仍待联调 | + +## 5. 待决问题 + +同域认证入口的 Nginx 路由和自建身份服务均未实施。完成前不能将地址建议视为可用认证入口。 diff --git a/frontend/src/components/OpenVPNOIDCGuide.vue b/frontend/src/components/OpenVPNOIDCGuide.vue index 7d0980c..b68701c 100644 --- a/frontend/src/components/OpenVPNOIDCGuide.vue +++ b/frontend/src/components/OpenVPNOIDCGuide.vue @@ -29,7 +29,9 @@
{{ $t('oidcGuide.secretTip') }}
- + + {{ $t('oidcGuide.reuseDomain') }} +
{{ $t('oidcGuide.linkedDomain') }}
{{ $t('oidcGuide.baseTip') }}
@@ -64,8 +66,16 @@ async function loadReadiness() { try { const { data } = await api.get('/tunnels/openvpn/oidc-readiness') readiness.value = data + if (!props.editing && !props.config.oidc_base_url && data.https_management_ready && /^[a-z0-9.-]+$/i.test(data.management_domain || '')) { + props.config.oidc_base_url = `https://${data.management_domain}` + } } catch { /* Old servers do not provide a readiness endpoint. */ } } +const suggestedBaseUrl = computed(() => { + const status = readiness.value + return status?.https_management_ready && /^[a-z0-9.-]+$/i.test(status.management_domain || '') + ? `https://${status.management_domain}` : '' +}) async function requestPort(from, direction, previous = null) { portLoading.value = true try { @@ -105,6 +115,7 @@ const guideStep = computed(() => !props.config.oidc_client_id ? 0 .guide-alert p { margin: 8px 0 0; line-height: 1.5; } .guide-alert ol { padding-left: 20px; line-height: 1.7; } .field-tip { margin-top: 4px; color: var(--text-secondary); font-size: 12px; line-height: 1.5; } +.reuse-domain { margin: 4px 0 0; } .port-controls { display: flex; gap: 6px; align-items: center; } code { overflow-wrap: anywhere; } @media (max-width: 720px) { .guide-steps { overflow-x: auto; justify-content: flex-start; } .guide-steps :deep(.el-step) { min-width: 120px; } } diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 8a75ee2..29afa27 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -229,7 +229,7 @@ "title": "Feishu / OIDC browser authentication", "externalService": "Requires openvpn-auth-oauth2", "componentReady": "Authentication component installed v{version}", - "authEntryPending": "Management TLS is ready at {domain}; OpenVPN authentication still requires a separate HTTPS hostname and an OIDC issuer.", + "authEntryPending": "HTTPS is ready at {domain}; the auth component's public callback route is not yet connected and an OIDC issuer is still needed.", "app": "Create app", "appShort": "Feishu developer console", "identity": "Enter identity settings", @@ -254,7 +254,8 @@ "keepSecret": "Leave blank to retain current secret", "secretTip": "Encrypted server-side and stored only in the auth service's 0600 configuration file.", "baseUrl": "Public sign-in URL", - "baseTip": "Use a public HTTPS root URL, not the current HTTP admin address. The auth component handles browser callbacks; its entry site may share the admin server.", + "baseTip": "Automatic filling reuses the domain and certificate only. The management site does not yet proxy OAuth2 paths to the auth component. Sign-in needs that Nginx route. Recheck saved tunnel callbacks if the domain changes.", + "reuseDomain": "Use current public domain", "linkedDomain": "Using the HTTPS domain from system settings; you can edit it.", "listenPort": "Local auth service port", "portTip": "Listens only on 127.0.0.1; no public access needed. New tunnels increment from 19090; +/- and manual entry skip configured and locally occupied ports.", "portLookupFailed": "Could not find an available port. Retry or enter one manually.", diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index 3570fc7..7ded3ca 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -229,7 +229,7 @@ "title": "飞书 / OIDC 浏览器认证配置", "externalService": "需要 openvpn-auth-oauth2", "componentReady": "认证组件已安装 v{version}", - "authEntryPending": "管理域名 {domain} 的证书已就绪;OpenVPN 认证入口仍需独立 HTTPS 域名与 OIDC 发行者。", + "authEntryPending": "{domain} 的 HTTPS 已就绪;认证组件的公网回调路由尚未接通,仍需配置 OIDC 发行者。", "app": "创建应用", "appShort": "飞书开放平台", "identity": "填写身份信息", @@ -254,7 +254,8 @@ "keepSecret": "留空保持原密钥", "secretTip": "仅保存在服务端加密存储与 0600 的认证服务配置文件内。", "baseUrl": "认证入口公网地址", - "baseTip": "填写可公网访问的 HTTPS 域名根地址;不能用当前 HTTP 管理地址。浏览器回调由认证组件处理,入口站点可与管理后台同机部署。", + "baseTip": "自动填写仅复用域名和证书;当前管理站点尚未转发认证组件的 OAuth2 路径。接通 Nginx 回调路由前不能完成登录。修改域名后需核对已保存专线的回调地址。", + "reuseDomain": "使用当前公网域名", "linkedDomain": "已引用系统设置中的 HTTPS 域名;可手动修改。", "listenPort": "本机认证服务端口", "portTip": "仅监听本机 127.0.0.1,无需公网开放。新建专线自动从 19090 起递增;加减或手动输入会跳过已配置和本机正在监听的端口。", "portLookupFailed": "无法获取可用端口,请稍后重试或手动选择",