import React, { useEffect, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { authService } from '../services/authService'; import { Loader2, CheckCircle2, AlertCircle } from 'lucide-react'; const API_BASE = import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:8010'; /** * SSO 回调页面 * * 支持两种模式: * 1. OAuth2 授权码模式:统一认证平台跳转携带 code 参数 * URL: /sso-callback?code=xxx * 2. 旧模式兼容:携带 sso_token 参数(直接验证 token) * URL: /sso-callback?sso_token=xxx&redirect=/models */ const SSOCallback: React.FC = () => { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const [status, setStatus] = useState<'loading' | 'success' | 'error'>('loading'); const [message, setMessage] = useState('正在验证身份...'); useEffect(() => { const code = searchParams.get('code'); const ssoToken = searchParams.get('sso_token'); let redirect = searchParams.get('redirect') || '/'; // 安全归一化 const forbidden = ['/login', '/register', '/sso-callback']; if (!redirect || forbidden.includes(redirect)) { redirect = '/'; } if (code) { // OAuth2 授权码模式:用 code 换取本地 token handleOAuth2Code(code, redirect); } else if (ssoToken) { // 旧模式兼容:直接用 sso_token 登录 handleSsoToken(ssoToken, redirect); } else { setStatus('error'); setMessage('缺少认证参数,请从统一认证平台重新登录'); setTimeout(() => navigate('/login'), 3000); } }, []); const handleOAuth2Code = async (code: string, redirect: string) => { try { const response = await fetch(`${API_BASE}/api/oauth/exchange-code`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code }) }); const result = await response.json(); if (result.code === 200 && result.data?.token) { // 保存 token 和用户信息 const { token, user } = result.data; authService.setToken(token, user); setStatus('success'); setMessage('登录成功,正在跳转...'); setTimeout(() => navigate(redirect, { replace: true }), 1000); } else { setStatus('error'); setMessage(result.detail || result.message || 'SSO 登录失败'); setTimeout(() => navigate('/login'), 3000); } } catch (err) { setStatus('error'); setMessage(err instanceof Error ? err.message : 'SSO 登录失败,请稍后重试'); setTimeout(() => navigate('/login'), 3000); } }; const handleSsoToken = async (ssoToken: string, redirect: string) => { try { const response = await authService.ssoLogin(ssoToken); if (response.code === 200) { setStatus('success'); setMessage('登录成功,正在跳转...'); setTimeout(() => navigate(redirect, { replace: true }), 1000); } else { setStatus('error'); setMessage(response.message || 'SSO 登录失败'); setTimeout(() => navigate('/login'), 3000); } } catch (err) { setStatus('error'); setMessage(err instanceof Error ? err.message : 'SSO 登录失败,请稍后重试'); setTimeout(() => navigate('/login'), 3000); } }; return (
{message}
> )} {status === 'success' && ( <>{message}
> )} {status === 'error' && ( <>{message}
3秒后自动跳转到登录页面
> )}