From 8dd01254ead3d9f093233ab9a035dc782a37c0b8 Mon Sep 17 00:00:00 2001 From: qikongjian Date: Sun, 21 Sep 2025 01:12:25 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=B7=E6=AD=8C=E7=99=BB=E5=BD=95=E5=9B=9E?= =?UTF-8?q?=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/auth/google/callback/route.ts | 93 ++++++++++++++++++++++++++- app/users/oauth/callback/page.tsx | 9 ++- components/auth/auth-guard.tsx | 2 +- lib/auth.ts | 22 ++++--- 4 files changed, 111 insertions(+), 15 deletions(-) diff --git a/app/api/auth/google/callback/route.ts b/app/api/auth/google/callback/route.ts index 101723b..7ffaa18 100644 --- a/app/api/auth/google/callback/route.ts +++ b/app/api/auth/google/callback/route.ts @@ -21,6 +21,50 @@ export async function POST(request: NextRequest) { ); } + // 开发模式:使用测试环境的OAuth处理 + const isDevelopment = process.env.NODE_ENV === 'development'; + const useTestEnv = isDevelopment; // 开发环境默认使用测试环境 + + if (useTestEnv) { + console.log('🧪 开发模式:使用模拟OAuth响应'); + + // 解析state参数获取origin信息 + let stateData: any = {}; + try { + stateData = JSON.parse(state); + } catch (e) { + console.warn('无法解析state参数:', state); + } + + // 模拟成功的OAuth响应 + const mockResponse = { + success: true, + data: { + token: 'dev-mock-token-' + Date.now(), + user: { + userId: 'dev-user-' + Math.random().toString(36).substr(2, 9), + userName: 'Development User', + name: 'Dev User', + email: 'dev@movieflow.com', + authType: 'GOOGLE', + isNewUser: false + }, + userInfo: { + userId: 'dev-user-' + Math.random().toString(36).substr(2, 9), + userName: 'Development User', + name: 'Dev User', + email: 'dev@movieflow.com', + authType: 'GOOGLE', + isNewUser: false + }, + message: 'Development mode - Google authentication simulated' + } + }; + + console.log('返回模拟OAuth响应:', mockResponse); + return NextResponse.json(mockResponse); + } + // 解析state参数 let stateData: any = {}; try { @@ -57,7 +101,10 @@ export async function POST(request: NextRequest) { ); } - const tokenResponse = await fetch('https://oauth2.googleapis.com/token', { + console.log('开始向Google交换token...'); + + // 创建fetch配置,包含超时和重试机制 + const fetchOptions = { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', @@ -69,8 +116,32 @@ export async function POST(request: NextRequest) { redirect_uri: getRedirectUri(request), grant_type: 'authorization_code', }), - }); + // 增加超时时间到30秒 + signal: AbortSignal.timeout(30000) + }; + let tokenResponse; + try { + tokenResponse = await fetch('https://oauth2.googleapis.com/token', fetchOptions); + } catch (fetchError: any) { + console.error('Google API连接失败:', fetchError.message); + + // 如果是超时错误,提供更友好的错误信息 + if (fetchError.name === 'TimeoutError' || fetchError.code === 'UND_ERR_CONNECT_TIMEOUT') { + return NextResponse.json( + { + success: false, + message: 'Google authentication service is temporarily unavailable. Please check your network connection and try again.' + }, + { status: 503 } + ); + } + + throw fetchError; + } + + console.log('Google token exchange响应状态:', tokenResponse.status); + if (!tokenResponse.ok) { const errorText = await tokenResponse.text(); console.error('Google token exchange failed:', errorText); @@ -84,6 +155,7 @@ export async function POST(request: NextRequest) { } const tokenData = await tokenResponse.json(); + console.log('Google token exchange成功,获得token'); const { id_token } = tokenData; if (!id_token) { @@ -99,6 +171,7 @@ export async function POST(request: NextRequest) { // 第二步:使用id_token调用Java后端 const javaBaseUrl = process.env.NEXT_PUBLIC_JAVA_URL || 'https://77.app.java.auth.qikongjian.com'; + console.log('开始调用Java后端:', javaBaseUrl); const backendResponse = await fetch(`${javaBaseUrl}/api/auth/google/login`, { method: 'POST', @@ -113,6 +186,7 @@ export async function POST(request: NextRequest) { }) }); + console.log('Java后端响应状态:', backendResponse.status); const backendResult = await backendResponse.json(); if (!backendResponse.ok || !backendResult.success) { @@ -144,6 +218,18 @@ export async function POST(request: NextRequest) { } catch (error: any) { console.error('Google OAuth回调处理错误:', error); + // 检查是否是网络连接错误 + if (error.code === 'ECONNREFUSED' || error.message?.includes('fetch failed')) { + console.error('网络连接失败,可能是Java后端服务不可用'); + return NextResponse.json( + { + success: false, + message: 'Backend service unavailable. Please try again later.' + }, + { status: 503 } + ); + } + return NextResponse.json( { success: false, @@ -159,9 +245,10 @@ export async function POST(request: NextRequest) { */ function getRedirectUri(request: NextRequest): string { const host = request.headers.get('host') || ''; - const protocol = request.headers.get('x-forwarded-proto') || 'https'; if (host.includes('localhost') || host.includes('127.0.0.1')) { + // 本地开发环境:使用实际的端口号(可能是3000或3001) + const protocol = 'http'; return `${protocol}://${host}/api/auth/google/callback`; } else if (host.includes('movieflow.net')) { return 'https://www.movieflow.net/api/auth/google/callback'; diff --git a/app/users/oauth/callback/page.tsx b/app/users/oauth/callback/page.tsx index fd996d4..7777e2a 100644 --- a/app/users/oauth/callback/page.tsx +++ b/app/users/oauth/callback/page.tsx @@ -16,6 +16,8 @@ export default function OAuthCallback() { useEffect(() => { const handleOAuthCallback = async () => { try { + console.log('OAuth回调页面开始处理...'); + // 获取URL参数 const params: OAuthCallbackParams = { code: searchParams.get("code") || undefined, @@ -24,8 +26,11 @@ export default function OAuthCallback() { error_description: searchParams.get("error_description") || undefined, }; + console.log('获取到的URL参数:', params); + // 检查是否有错误 if (params.error) { + console.error('OAuth错误:', params.error, params.error_description); setStatus("error"); setMessage(params.error_description || `OAuth error: ${params.error}`); return; @@ -33,6 +38,7 @@ export default function OAuthCallback() { // 验证必需参数 if (!params.code || !params.state) { + console.error('缺少必需的OAuth参数:', { code: !!params.code, state: !!params.state }); setStatus("error"); setMessage("Missing required OAuth parameters"); return; @@ -42,8 +48,9 @@ export default function OAuthCallback() { let stateData: any = {}; try { stateData = JSON.parse(params.state); + console.log('解析后的State数据:', stateData); } catch (e) { - console.warn('无法解析state参数:', params.state); + console.warn('无法解析state参数:', params.state, e); } console.log('开始处理Google OAuth回调, code:', params.code?.substring(0, 20) + '...'); diff --git a/components/auth/auth-guard.tsx b/components/auth/auth-guard.tsx index 2699e6d..bd6ada4 100644 --- a/components/auth/auth-guard.tsx +++ b/components/auth/auth-guard.tsx @@ -18,7 +18,7 @@ export default function AuthGuard({ children }: AuthGuardProps) { const pathname = usePathname(); // 不需要鉴权的页面 - const publicPaths = ['/','/login', '/signup', '/forgot-password', '/Terms', '/Privacy', '/activate']; + const publicPaths = ['/','/login', '/signup', '/forgot-password', '/Terms', '/Privacy', '/activate', '/users/oauth/callback']; const isPublicPath = publicPaths.includes(pathname); useEffect(() => { diff --git a/lib/auth.ts b/lib/auth.ts index 8c727dc..07aa2e7 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -252,16 +252,18 @@ export const signInWithGoogle = async (inviteCode?: string): Promise => { const isProdEnv = window.location.hostname.includes('movieflow.ai'); let redirectUri; - if (isLocalhost) { - redirectUri = `${window.location.origin}/api/auth/google/callback`; - } else if (isDevEnv) { - redirectUri = 'https://www.movieflow.net/api/auth/google/callback'; // 指向正确的API端点 - } else if (isProdEnv) { - redirectUri = 'https://www.movieflow.ai/api/auth/google/callback'; // 指向正确的API端点 - } else { - // 默认使用生产环境 - redirectUri = 'https://www.movieflow.ai/api/auth/google/callback'; // 指向正确的API端点 - } + redirectUri = 'https://www.movieflow.net/api/auth/google/callback'; + // if (isLocalhost) { + // // 本地开发环境:仍然使用本地地址,但后端会转发到测试环境处理 + // redirectUri = `${window.location.origin}/api/auth/google/callback`; + // } else if (isDevEnv) { + // // 指向正确的API端点 + // } else if (isProdEnv) { + // redirectUri = 'https://www.movieflow.ai/api/auth/google/callback'; // 指向正确的API端点 + // } else { + // // 默认使用生产环境 + // redirectUri = 'https://www.movieflow.ai/api/auth/google/callback'; // 指向正确的API端点 + // } console.log('使用的redirect_uri:', redirectUri);