From 52d5827932cbd9c8e38885044768278647ba5648 Mon Sep 17 00:00:00 2001 From: bigcode Date: Thu, 1 Oct 2026 21:30:46 +0800 Subject: [PATCH] =?UTF-8?q?v2.9.1:=20=E7=BB=9F=E4=B8=80=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E5=8D=95=E7=94=A8=E6=88=B7=E5=8C=96=E2=80=94=E2=80=94=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20JIT=20=E5=BC=80=E5=85=B3=E4=B8=8E=20oidc=5Fidentiti?= =?UTF-8?q?es=20=E6=98=A0=E5=B0=84=E8=A1=A8(0007),=E4=BB=BB=E6=84=8F=20ZIT?= =?UTF-8?q?ADEL=20=E8=BA=AB=E4=BB=BD=E7=99=BB=E5=BD=95=E5=94=AF=E4=B8=80?= =?UTF-8?q?=E7=94=A8=E6=88=B7,=E4=B8=8A=E6=AC=A1=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E8=BA=AB=E4=BB=BD=E5=AD=98=20settings=20=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- console/frontend/src/api.ts | 12 +- .../frontend/src/components/SettingsModal.tsx | 43 +++---- console/frontend/src/pages/Login.tsx | 1 - console/src/routes/oidc.ts | 29 ++--- console/src/routes/settings.ts | 23 ++-- console/src/services/oidc.ts | 110 ++++++++---------- docs/12_ZITADEL_SSO.md | 27 ++--- docs/API.md | 10 +- migrations/0007_drop_oidc_identities.sql | 5 + package.json | 2 +- shared/src/ids.ts | 2 - tests/oidc-sso.test.ts | 76 +++++------- tests/ui-smoke.ts | 9 +- 13 files changed, 155 insertions(+), 194 deletions(-) create mode 100644 migrations/0007_drop_oidc_identities.sql diff --git a/console/frontend/src/api.ts b/console/frontend/src/api.ts index 5326f96..d372a02 100644 --- a/console/frontend/src/api.ts +++ b/console/frontend/src/api.ts @@ -338,21 +338,19 @@ export interface SettingsInfo { /** 实际请求的 scope(点号分隔,空格分隔多个) */ scope: string; }; - /** ZITADEL 统一登录配置与当前账号绑定情况 */ + /** ZITADEL 统一登录配置与上次登录身份 */ oidc: { issuer: string; client_id: string; enabled: boolean; - /** JIT:未绑定的统一登录身份自动创建本地用户(即管理员) */ - jit: boolean; /** settings = 后台设置;env = 部署变量兜底;none = 未配置 */ source: "settings" | "env" | "none"; /** 授权 scope(固定 openid profile) */ scopes: string; /** 需要在 ZITADEL 控制台应用里登记的回调地址 */ redirect_uri: string; - /** 当前账号已绑定的统一登录身份(未绑定为 null) */ - identity: { issuer: string; subject: string; display_name: string | null; email: string | null } | null; + /** 上次统一登录身份(展示用;单用户系统,登录即当前唯一账号) */ + last_login: { issuer: string; subject: string; display_name: string; email: string | null; at: string } | null; }; /** 需要在 Cloudflare Dashboard 登记的授权回调地址 */ redirect_uri: string; @@ -362,11 +360,11 @@ export const getSettings = () => api("/api/settings"); /** 保存设置 * webhook.key / cf_oauth.secret 语义一致:undefined 保留原值、空串清除、非空设置新值 - * oidc.enabled / oidc.jit 缺省表示沿用已保存的开关状态 */ + * oidc.enabled 缺省表示沿用已保存的开关状态 */ export const putSettings = (body: { webhook?: { url: string; headers: Record; key?: string }; cf_oauth?: { client_id: string; secret?: string; scope?: string }; - oidc?: { issuer: string; client_id: string; enabled?: boolean; jit?: boolean }; + oidc?: { issuer: string; client_id: string; enabled?: boolean }; }) => api("/api/settings", "PUT", body); /** # 成员变量: 授权配置自检结果 **/ diff --git a/console/frontend/src/components/SettingsModal.tsx b/console/frontend/src/components/SettingsModal.tsx index aebf874..0360ca7 100644 --- a/console/frontend/src/components/SettingsModal.tsx +++ b/console/frontend/src/components/SettingsModal.tsx @@ -5,7 +5,7 @@ * - Cloudflare OAuth 客户端(Client ID / Secret)也在设置里维护,Secret 加密存储只回 last4, * 保存后立即生效,无需重新部署;未配置时账号页「添加账号」不可用 * - ZITADEL 统一登录:issuer + Client ID(PKCE 公共客户端无 secret),回调地址 {origin}/auth/callback; - * 登录成功即管理员(本平台没有权限设置),JIT 自动建号可开关 + * 单用户系统(v2.9.1):统一登录成功即登录唯一管理员账号,没有权限设置与账号映射 * - 内容高度不超过屏幕(超出滚动) */ import { useCallback, useEffect, useState } from "react"; @@ -620,22 +620,20 @@ interface OidcFormValues { } /** # 函数 - * ZITADEL 统一登录 tab(v2.9.0):issuer + Client ID(PKCE 无 secret)+ 启用/JIT 开关; - * 回调地址需在 ZITADEL 控制台应用里登记;登录成功即管理员(本平台没有权限设置) + * ZITADEL 统一登录 tab(v2.9.0;v2.9.1 单用户化):issuer + Client ID(PKCE 无 secret)+ 启用开关; + * 回调地址需在 ZITADEL 控制台应用里登记;单用户系统——统一登录成功即登录本平台唯一账号 */ function ZitadelTab({ info, onSaved }: { info: SettingsInfo; onSaved: () => void }) { const { message } = App.useApp(); const [form] = Form.useForm(); const [saving, setSaving] = useState(false); const [enabled, setEnabled] = useState(info.oidc.enabled); - const [jit, setJit] = useState(info.oidc.jit); const meta = info.oidc; useEffect(() => { form.setFieldsValue({ issuer: meta.issuer, client_id: meta.client_id }); setEnabled(meta.enabled); - setJit(meta.jit); - }, [meta.issuer, meta.client_id, meta.enabled, meta.jit, form]); + }, [meta.issuer, meta.client_id, meta.enabled, form]); /** 保存统一登录配置 */ const save = async () => { @@ -643,7 +641,7 @@ function ZitadelTab({ info, onSaved }: { info: SettingsInfo; onSaved: () => void setSaving(true); try { await putSettings({ - oidc: { issuer: values.issuer.trim(), client_id: values.client_id.trim(), enabled, jit }, + oidc: { issuer: values.issuer.trim(), client_id: values.client_id.trim(), enabled }, }); message.success("ZITADEL 统一登录配置已保存"); onSaved(); @@ -681,8 +679,8 @@ function ZitadelTab({ info, onSaved }: { info: SettingsInfo; onSaved: () => void } description={ <> - 在 ZITADEL 控制台的应用 Redirect URI 里登记下面的回调地址;所有通过统一登录登录的用户都是 - 管理员(本平台没有权限设置)。 + 在 ZITADEL 控制台的应用 Redirect URI 里登记下面的回调地址。本平台是单用户系统:统一登录成功即登录 + 唯一的管理员账号,没有权限设置。 } /> @@ -719,12 +717,6 @@ function ZitadelTab({ info, onSaved }: { info: SettingsInfo; onSaved: () => void 启用后登录页显示「ZITADEL 统一登录」按钮;密码登录不受影响(双通道并存) - - - - 开启:未绑定的统一登录身份首次登录自动创建本地用户(即管理员);关闭:未绑定身份拒绝登录 - -