浏览器单点登录
# 浏览器单点登录
# 目的
让读者在 Vben 中完成租户或平台 OIDC 登录、同来源会话恢复,以及本地退出或统一退出。成功登录后进入工作台或改密页;统一退出失败时仍保持本地已撤销,并可十分钟内重试。
# 前置条件
schema v26、已登记的 Web client/provider 与精确外部绑定;APP_SSO 信任档案与密钥文件已配置。构建时设置公开 VITE_SSO_* 变量(不含 secret)。浏览器 Origin 与 API 一致,并带 X-App-Request。
本页说明 Vben 的平台/租户 SSO 登录、同来源恢复与退出。会员端继续使用独立 API 或原生验收客户端;服务凭据不进入浏览器登录。MySQL与真实ZITADEL的两个独立Web应用已完成登录、重载、到期刷新、故障补偿和签名统一退出;详见M5实施记录。
# 先准备服务端
显式迁移到 v26,登记当前 realm 的 Web 客户端,授权方式为 authorization_code;登记部署批准的 provider 和现有账号的精确 issuer/sub 绑定。身份不会按邮箱合并或自动创建。账号模式须允许 OIDC,租户/账号/client/provider/绑定及口令策略仍须当前有效。
配置 APP_SSO 的网络/issuer/回跳信任档案、材料密钥和需要的外部 client secret 文件;私有文件不能提交到仓库或放进 VITE 环境。反向代理将 /api/ 和 /oidc/ 转发给 API,浏览器页面与 API 使用同一公开 origin。生产继续强制统一 JWE;SSO 的业务 JSON 不绕过内容加密、Origin、限流或认证。
提供方回调使用正式固定路径;SPA 的 returnUrl 固定为本应用 /auth/sso/return,平台为 /platform/auth/sso/return。RP 的 postLogoutUrl 使用提供方对应的 /oidc/{realm}/{tenantId}/{providerCode}/logout-callback,不是 SPA 路径。
开发 HTTP 仅能显式批准字面 loopback origin。公共上游 none 客户端不能使用 HTTP RP 退出回跳;本地机密 Web 联调使用 client_secret_basic 和外部 secret 文件。该限制不因开发模式或原生授权端口例外而放宽。
# 配置前端的公开定位
每个应用构建时分别设置三项公开环境变量:
| 租户入口 | 平台入口 | 含义 |
|---|---|---|
VITE_SSO_ADMIN_CLIENT_ID | VITE_SSO_PLATFORM_CLIENT_ID | 本地注册的 Web clientId |
VITE_SSO_ADMIN_PROVIDER_ID | VITE_SSO_PLATFORM_PROVIDER_ID | 当前提供方数字 ID |
VITE_SSO_ADMIN_AUTHORITY | VITE_SSO_PLATFORM_AUTHORITY | 浏览器授权/退出端点的精确 origin |
AUTHORITY 不带路径、查询、片段或 userinfo,通常为 https://idp.example.invalid;开发构建才允许显式 http://127.0.0.1:端口。同一 realm 三项全部缺失时不显示 SSO 按钮,部分配置或不安全地址会拒绝启动流程。变量不包含上游 client secret、材料密钥、密码或 token。
租户管理端构建示例(平台入口改用 VITE_SSO_PLATFORM_*):
export VITE_SSO_ADMIN_CLIENT_ID=admin-web
export VITE_SSO_ADMIN_PROVIDER_ID=1
export VITE_SSO_ADMIN_AUTHORITY=https://idp.example.invalid
两个应用应使用各自的本地 client/provider 和精确 returnUrl/origin,IdP 中也登记各自应用。当前Vben按origin/realm协调身份;同origin路径下多套独立部署同时保留不同身份尚未验证。前端提示、Cookie 与本地会话来源不能替换成另一个应用的 client。
# 登录与恢复
租户登录页输入租户编码后点“使用单点登录”;平台入口不传租户编码。页面只向正式 start API 提交已配置定位,随后跳转到批准的 IdP origin。系统浏览器和 IdP 负责用户认证;固定回调消费一次 state/授权码,完成后回到固定 SPA 落点。
发起授权(开发/测试明文;providerId/clientId 与构建变量一致):
POST /api/admin/v1/auth/sso/start
Origin: http://127.0.0.1:5174
X-App-Request: admin
Content-Type: application/json
{
"providerId": "1",
"clientId": "admin-web",
"tenantCode": "example"
}
成功时 data 含浏览器应跳转的授权地址(字段以 OpenAPI SSOAuthorization 为准),刷新凭证仍只经后续回调与 Cookie 交付,不出现在此 JSON。
返回页只根据本标签短期动作区分登录与退出,不读取 URL 中的 token/code,不把 access 写入跳转 URL。登录落地调用本应用专属 SSO refresh,真实刷新凭据留在 HttpOnly Cookie;mustChangePassword=true 直接进入固定改密页,不先加载 me/codes/menus。
access 只在内存。重载恢复和 401001 自动刷新始终使用当前认证来源;SSO 失败不会退回口令 Cookie。401002 与权限拒绝不刷新。启用 SSO 而没有来源提示时,必须显式选择登录;未启用 SSO 的旧口令部署保留原恢复行为。
浏览器只持久化公开的方法/client 提示以及本标签十分钟动作/退出重试标记;这些值不具有身份授权能力。存储不可用或提示损坏时拒绝自动恢复。跨标签 Cookie 轮换由 Web Locks 串行,同域身份版本变化后不能加入旧版本的在途刷新。
# 本地退出与统一退出
右上角账号菜单的“退出登录”只撤销当前应用的本地会话。SSO 会话在同一账号菜单另显示“统一退出”:先提交本地撤销,再准备上游 RP 跳转。页面清内存/动态权限并广播本 origin 的退出事件;准备失败明确显示本地已退、上游未确认,提供十分钟内的“重试统一退出”。不会因上游故障恢复已撤销身份,也不会自动重新登录。
重试依赖服务端仍保留的失效 HttpOnly Cookie 与有界加密材料,不在浏览器保存 hint 或退出 URL。收到固定退出返回只表示该次 RP 关联完成;其他应用真正失效应由已验证签名的 backchannel 通知及其当前 API 拒绝证明。
浏览器不支持 Web Locks 时停止自动恢复/刷新,操作者须重新登录;真实网络、IdP 或配置错误使用公开提示,不输出内部错误链或协议材料。
# 本轮验证范围
真实浏览器使用独占MySQL/Redis/API、两个独立Web客户端/provider和ZITADEL v4.20.0。第二应用复用既有IdP会话,无须重复输入凭据;两应用重载及实际access到期后仍能读取本人页面。停止IdP后,A本地撤销而B保持有效;恢复同一IdP后,A显式重试RP退出,B当前API被拒绝。读回确认2个OIDC会话均撤销/清材料、2条签名退出事件,以及7次SSO恢复/刷新、0次口令刷新。
该真实IdP场景采用显式开发loopback HTTP及机密Web上游,不代表生产HTTPS、任意IdP或全OS认证。三域、两种JWE套件和Cookie边界由另外的真实TCP/TLS协议测试覆盖。实例、数据库、Redis、浏览器页和私有secret均已清理;本页不提供创建云资源或公开服务的步骤。