const gatewayAPIBase = (import.meta.env.VITE_GATEWAY_API_BASE_URL ?? 'http://localhost:8088').replace(/\/$/, ''); export type OIDCRuntimeConfiguration = { enabled: boolean; oidcLogin: boolean; loginUrl?: string; logoutUrl?: string; status: string; }; const disabledRuntime: OIDCRuntimeConfiguration = { enabled: false, oidcLogin: false, status: 'disabled' }; let runtimeConfiguration = disabledRuntime; let runtimeLoaded = false; let runtimeRequest: Promise | null = null; export type OIDCCallbackError = { code: string; reason?: string; diagnosticId?: string; message: string; retryable: boolean; }; const callbackErrors: Record> = { OIDC_LOGIN_INVALID: { message: '统一认证登录事务无效或已过期,请重新登录', retryable: true }, OIDC_TOKEN_EXCHANGE_FAILED: { message: '统一认证登录结果无效,请重新登录', retryable: false }, OIDC_SESSION_STORE_UNAVAILABLE: { message: '登录会话存储暂时不可用,请稍后重试', retryable: false }, GATEWAY_USER_NOT_PROVISIONED: { message: '该账号尚未开通 EasyAI Gateway', retryable: false }, GATEWAY_USER_DISABLED: { message: '该 Gateway 账号已停用,请联系管理员', retryable: false }, GATEWAY_TENANT_UNAVAILABLE: { message: 'Gateway 租户尚未就绪,请联系管理员', retryable: false }, }; const loginTransactionFailureMessages: Record = { COOKIE_MISSING: '浏览器未携带统一认证登录事务 Cookie,请允许 localhost Cookie 后重新登录', TRANSACTION_INVALID: '统一认证登录事务无法验证或已过期,请重新登录', STATE_MISMATCH: '认证回调与当前登录事务不匹配,请关闭重复登录页面后重新登录', AUTHORIZATION_RESPONSE_MISSING: '认证中心回调缺少必要参数,请重新登录', }; export function oidcLoginEnabled() { return runtimeConfiguration.enabled && runtimeConfiguration.oidcLogin; } export function oidcBrowserSessionEnabled() { return oidcLoginEnabled(); } export async function loadOIDCRuntimeConfiguration(force = false): Promise { if (!force && runtimeLoaded) return runtimeConfiguration; if (!force && runtimeRequest) return runtimeRequest; runtimeRequest = fetch(`${gatewayAPIBase}/api/v1/public/identity`, { credentials: 'include', headers: { Accept: 'application/json' }, }).then(async (response) => { if (!response.ok) return disabledRuntime; const value = await response.json() as Partial; if (typeof value.enabled !== 'boolean' || typeof value.oidcLogin !== 'boolean' || typeof value.status !== 'string') { return disabledRuntime; } return { enabled: value.enabled, oidcLogin: value.oidcLogin, status: value.status, ...(typeof value.loginUrl === 'string' ? { loginUrl: value.loginUrl } : {}), ...(typeof value.logoutUrl === 'string' ? { logoutUrl: value.logoutUrl } : {}), }; }).catch(() => disabledRuntime).then((configuration) => { runtimeConfiguration = configuration; runtimeLoaded = true; runtimeRequest = null; return configuration; }); return runtimeRequest; } export async function startOIDCLogin() { const configuration = await loadOIDCRuntimeConfiguration(true); if (!configuration.enabled || !configuration.oidcLogin || !configuration.loginUrl) throw new Error('统一认证未配置'); const returnTo = `${window.location.pathname}${window.location.search}${window.location.hash}` || '/'; const loginURL = new URL(identityEndpointURL(configuration.loginUrl), window.location.origin); loginURL.searchParams.set('returnTo', returnTo.startsWith('/') ? returnTo : '/'); window.location.assign(loginURL.toString()); } export async function startOIDCLogout() { const configuration = await loadOIDCRuntimeConfiguration(true); if (!configuration.enabled || !configuration.oidcLogin || !configuration.logoutUrl) return false; const form = document.createElement('form'); form.method = 'POST'; form.action = identityEndpointURL(configuration.logoutUrl); form.style.display = 'none'; document.body.appendChild(form); form.submit(); return true; } function identityEndpointURL(path: string) { if (/^https:\/\//i.test(path) || /^http:\/\/(localhost|127\.0\.0\.1)(:|\/)/i.test(path)) return path; return `${gatewayAPIBase}/${path.replace(/^\//, '')}`; } export function consumeOIDCCallbackError() { const params = new URLSearchParams(window.location.search); const code = params.get('oidcError') ?? ''; if (!code) return null; const rawReason = params.get('oidcErrorReason') ?? ''; const reason = code === 'OIDC_LOGIN_INVALID' && loginTransactionFailureMessages[rawReason] ? rawReason : ''; const rawDiagnosticId = params.get('oidcDiagnosticId') ?? ''; const diagnosticId = /^[A-Za-z0-9_-]{6,64}$/.test(rawDiagnosticId) ? rawDiagnosticId : ''; params.delete('oidcError'); params.delete('oidcErrorReason'); params.delete('oidcDiagnosticId'); const query = params.toString(); window.history.replaceState({}, '', `${window.location.pathname}${query ? `?${query}` : ''}${window.location.hash}`); const callbackError = callbackErrors[code] ?? { message: '统一认证登录失败,请重试', retryable: false }; return { code, ...(reason ? { reason } : {}), ...(diagnosticId ? { diagnosticId } : {}), ...callbackError, ...(reason ? { message: loginTransactionFailureMessages[reason] } : {}), }; }