diff --git a/apps/DocFlow/src/app/auth/callback/page.tsx b/apps/DocFlow/src/app/auth/callback/page.tsx index 34133d4b..7beac285 100644 --- a/apps/DocFlow/src/app/auth/callback/page.tsx +++ b/apps/DocFlow/src/app/auth/callback/page.tsx @@ -6,158 +6,161 @@ import { CheckCircle, Loader2, AlertCircle } from 'lucide-react'; import { useGitHubLogin, useTokenLogin } from '@/hooks/useAuth'; +const DEFAULT_REDIRECT = '/dashboard'; +const REDIRECT_STORAGE_KEY = 'auth_redirect'; + +function safeDecode(value: string | null): string | null { + if (!value) return null; + + try { + return decodeURIComponent(value); + } catch { + return value; + } +} + +function parseOptionalInt(value: string | null): number | undefined { + if (value == null || value === '') return undefined; + + const n = Number(value); + + return Number.isFinite(n) ? n : undefined; +} + +type CallbackState = 'loading' | 'success' | 'error'; + function CallbackContent() { const [status, setStatus] = useState('处理中...'); - const [state, setState] = useState<'loading' | 'success' | 'error'>('loading'); + const [uiState, setUiState] = useState('loading'); const [mounted, setMounted] = useState(false); - const [authProcessed, setAuthProcessed] = useState(false); // 添加认证处理标记 + const [processed, setProcessed] = useState(false); const searchParams = useSearchParams(); const router = useRouter(); const gitHubLoginMutation = useGitHubLogin(); const tokenLoginMutation = useTokenLogin(); - // 确保组件在客户端挂载 useEffect(() => { setMounted(true); }, []); - // 获取重定向 URL const getRedirectUrl = (): string => { - // 1. 优先从 state 参数获取(GitHub OAuth 标准) - const state = searchParams?.get('state'); + const stateParam = safeDecode(searchParams?.get('state') ?? null); - if (state) { - try { - return decodeURIComponent(state); - } catch {} + if (stateParam) { + return stateParam; } - // 2. 从 redirect_to 参数获取 - const redirectTo = searchParams?.get('redirect_to'); + const redirectTo = safeDecode(searchParams?.get('redirect_to') ?? null); if (redirectTo) { - try { - return decodeURIComponent(redirectTo); - } catch {} + return redirectTo; } - // 3. 从 sessionStorage 获取(仅客户端) - if (mounted && typeof window !== 'undefined') { - try { - const saved = sessionStorage.getItem('auth_redirect'); + if (typeof window !== 'undefined') { + const saved = sessionStorage.getItem(REDIRECT_STORAGE_KEY); - if (saved) { - sessionStorage.removeItem('auth_redirect'); + if (saved) { + sessionStorage.removeItem(REDIRECT_STORAGE_KEY); - return saved; - } - } catch {} + return saved; + } } - // 4. 默认跳转到仪表盘 - return '/dashboard'; + return DEFAULT_REDIRECT; }; useEffect(() => { - if (!mounted || authProcessed || !searchParams) return; - - const processAuth = async () => { - setAuthProcessed(true); - - try { - // 场景1: 直接 Token 登录 - const token = searchParams.get('token'); - - if (token) { - const authData = { - token, - refresh_token: searchParams.get('refresh_token') || undefined, - expires_in: searchParams.get('expires_in') - ? parseInt(searchParams.get('expires_in')!) - : undefined, - refresh_expires_in: searchParams.get('refresh_expires_in') - ? parseInt(searchParams.get('refresh_expires_in')!) - : undefined, - }; - - setStatus('登录成功,正在跳转...'); - setState('success'); - - tokenLoginMutation.mutate({ - authData, - redirectUrl: getRedirectUrl(), - }); - - return; - } - - // 场景2: GitHub OAuth 授权码登录 - const code = searchParams.get('code'); - - if (!code) { - setStatus('缺少授权码,请重新登录'); - setState('error'); - - return; - } - - setStatus('正在验证授权...'); - - gitHubLoginMutation.mutate( - { - code, - redirectUrl: getRedirectUrl(), + if (!mounted || processed) return; + + setProcessed(true); + + const redirectUrl = getRedirectUrl(); + const token = searchParams.get('token'); + + if (token) { + setStatus('登录成功,正在跳转...'); + setUiState('success'); + tokenLoginMutation.mutate({ + authData: { + token, + refresh_token: searchParams.get('refresh_token') ?? undefined, + expires_in: parseOptionalInt(searchParams.get('expires_in')), + refresh_expires_in: parseOptionalInt(searchParams.get('refresh_expires_in')), + }, + redirectUrl, + }); + + return; + } + + const code = searchParams.get('code'); + + if (code) { + setStatus('正在验证授权...'); + gitHubLoginMutation.mutate( + { code, redirectUrl }, + { + onSuccess: () => { + setStatus('登录成功,正在跳转...'); + setUiState('success'); }, - { - onSuccess: () => { - setStatus('登录成功,正在跳转...'); - setState('success'); - }, - onError: (error) => { - const message = error instanceof Error ? error.message : String(error); - setStatus(`认证失败: ${message}`); - setState('error'); - }, + onError: (error) => { + setStatus(`认证失败:${error instanceof Error ? error.message : String(error)}`); + setUiState('error'); }, - ); - } catch (error) { - const message = error instanceof Error ? error.message : '未知错误'; - setStatus(`登录失败: ${message}`); - setState('error'); - } - }; + }, + ); + + return; + } + + setStatus('缺少授权信息,请重新登录'); + setUiState('error'); + }, [mounted, processed, searchParams]); - processAuth(); - }, [mounted, authProcessed, searchParams]); + const handleManualRedirect = () => router.push(getRedirectUrl()); return (
-

GitHub认证

- -
- {state === 'loading' && ( +

登录

+ +
+ {uiState === 'loading' && (
- +

{status}

)} - {state === 'success' && ( -
- + {uiState === 'success' && ( +
+

{status}

+
)} - {state === 'error' && ( + {uiState === 'error' && (
- +

{status}