diff --git a/apps/web/src/lib/oidc.test.ts b/apps/web/src/lib/oidc.test.ts index 8a04a9c..78810c7 100644 --- a/apps/web/src/lib/oidc.test.ts +++ b/apps/web/src/lib/oidc.test.ts @@ -26,6 +26,32 @@ describe('OIDC BFF navigation', () => { expect(target.searchParams.has('code_challenge')).toBe(false); }); + it('resolves the production relative API base against the browser origin', async () => { + vi.stubEnv('VITE_GATEWAY_API_BASE_URL', '/gateway-api'); + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ + ok: true, + json: async () => ({ + enabled: true, + oidcLogin: true, + loginUrl: '/api/v1/auth/oidc/login', + logoutUrl: '/api/v1/auth/oidc/logout', + status: 'active', + }), + })); + const assign = vi.fn(); + vi.stubGlobal('window', { + location: { origin: 'https://ai.51easyai.com', pathname: '/workspace/overview', search: '', hash: '', assign }, + }); + + const { startOIDCLogin } = await import('./oidc'); + await startOIDCLogin(); + + const target = new URL(String(assign.mock.calls[0]?.[0])); + expect(target.origin).toBe('https://ai.51easyai.com'); + expect(target.pathname).toBe('/gateway-api/api/v1/auth/oidc/login'); + expect(target.searchParams.get('returnTo')).toBe('/workspace/overview'); + }); + it('submits logout as a top-level POST without exposing tokens', async () => { vi.stubEnv('VITE_GATEWAY_API_BASE_URL', 'https://gateway.example.com/gateway-api'); vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ diff --git a/apps/web/src/lib/oidc.ts b/apps/web/src/lib/oidc.ts index 5c39cd0..40a0a89 100644 --- a/apps/web/src/lib/oidc.ts +++ b/apps/web/src/lib/oidc.ts @@ -77,7 +77,7 @@ 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)); + const loginURL = new URL(identityEndpointURL(configuration.loginUrl), window.location.origin); loginURL.searchParams.set('returnTo', returnTo.startsWith('/') ? returnTo : '/'); window.location.assign(loginURL.toString()); }