Refactor app instance to Keycloak SSO
This commit is contained in:
68
app-instance/frontend/app/auth/callback/page.tsx
Normal file
68
app-instance/frontend/app/auth/callback/page.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import {
|
||||
clearLoginState,
|
||||
exchangeKeycloakCallback,
|
||||
loadLoginState,
|
||||
parseAuthCallbackUrl,
|
||||
} from '@/lib/keycloak-oidc';
|
||||
import { getMe } from '@/lib/api';
|
||||
import { pickAppText } from '@/lib/i18n/core';
|
||||
import { useAppI18n } from '@/lib/i18n/provider';
|
||||
import { useChatStore } from '@/lib/store';
|
||||
|
||||
export default function AuthCallbackPage() {
|
||||
const { locale } = useAppI18n();
|
||||
const router = useRouter();
|
||||
const setUser = useChatStore((s) => s.setUser);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
const completeLogin = async () => {
|
||||
const callback = parseAuthCallbackUrl();
|
||||
if (callback.error) {
|
||||
throw new Error(callback.errorDescription || callback.error);
|
||||
}
|
||||
if (!callback.code || !callback.state) {
|
||||
throw new Error('Missing Keycloak callback code or state');
|
||||
}
|
||||
const loginState = loadLoginState();
|
||||
if (!loginState || loginState.state !== callback.state) {
|
||||
throw new Error('Invalid Keycloak login state');
|
||||
}
|
||||
|
||||
const result = await exchangeKeycloakCallback({ code: callback.code, state: loginState });
|
||||
clearLoginState();
|
||||
const user = await getMe().catch(() => result.user);
|
||||
if (cancelled) return;
|
||||
setUser(user);
|
||||
router.replace(loginState.nextPath || '/');
|
||||
};
|
||||
|
||||
completeLogin().catch((exc) => {
|
||||
clearLoginState();
|
||||
if (!cancelled) {
|
||||
setError(exc instanceof Error ? exc.message : String(exc));
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [router, setUser]);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center px-4">
|
||||
<div className="max-w-lg text-center text-sm text-muted-foreground">
|
||||
{error
|
||||
? pickAppText(locale, `登录失败:${error}`, `Sign-in failed: ${error}`)
|
||||
: pickAppText(locale, '正在完成登录...', 'Completing sign-in...')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user