From 735d90bbd7b3fae91d40c838144675ac7553d87b Mon Sep 17 00:00:00 2001 From: Zixin Zhou Date: Mon, 22 Sep 2025 20:33:43 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B4=A7=E6=80=A5=E5=9B=9E=E6=BB=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/auth/google/callback/route.ts | 194 +++++++++++--------------- 1 file changed, 83 insertions(+), 111 deletions(-) diff --git a/app/api/auth/google/callback/route.ts b/app/api/auth/google/callback/route.ts index 05b7337..6ec8ef4 100644 --- a/app/api/auth/google/callback/route.ts +++ b/app/api/auth/google/callback/route.ts @@ -13,21 +13,21 @@ export async function POST(request: NextRequest) { // 验证必需参数 if (!code || !state) { return NextResponse.json( - { - success: false, - message: 'Missing required parameters: code and state' - }, - { status: 400 } + { + success: false, + message: 'Missing required parameters: code and state' + }, + { status: 400 } ); } // 开发模式:使用测试环境的OAuth处理 const isDevelopment = process.env.NODE_ENV === 'development'; const useTestEnv = isDevelopment; // 开发环境默认使用测试环境 - + if (useTestEnv) { console.log('🧪 开发模式:使用模拟OAuth响应'); - + // 解析state参数获取origin信息 let stateData: any = {}; try { @@ -35,7 +35,7 @@ export async function POST(request: NextRequest) { } catch (e) { console.warn('无法解析state参数:', state); } - + // 模拟成功的OAuth响应 const mockResponse = { success: true, @@ -60,7 +60,7 @@ export async function POST(request: NextRequest) { message: 'Development mode - Google authentication simulated' } }; - + console.log('返回模拟OAuth响应:', mockResponse); return NextResponse.json(mockResponse); } @@ -72,11 +72,11 @@ export async function POST(request: NextRequest) { } catch (e) { console.warn('无法解析state参数:', state); return NextResponse.json( - { - success: false, - message: 'Invalid state parameter' - }, - { status: 400 } + { + success: false, + message: 'Invalid state parameter' + }, + { status: 400 } ); } @@ -89,20 +89,20 @@ export async function POST(request: NextRequest) { // 第一步:使用authorization code向Google换取access token和id_token const googleClientId = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || '847079918888-o1nne8d3ij80dn20qurivo987pv07225.apps.googleusercontent.com'; const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET || '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'; - + if (!googleClientSecret) { console.error('Google Client Secret未配置'); return NextResponse.json( - { - success: false, - message: 'Google Client Secret not configured' - }, - { status: 500 } + { + success: false, + message: 'Google Client Secret not configured' + }, + { status: 500 } ); } console.log('开始向Google交换token...'); - + // 创建fetch配置,包含超时和重试机制 const fetchOptions = { method: 'POST', @@ -125,32 +125,32 @@ export async function POST(request: NextRequest) { 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 } + { + 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); return NextResponse.json( - { - success: false, - message: 'Failed to exchange authorization code for tokens' - }, - { status: 400 } + { + success: false, + message: 'Failed to exchange authorization code for tokens' + }, + { status: 400 } ); } @@ -161,109 +161,81 @@ export async function POST(request: NextRequest) { if (!id_token) { console.error('No id_token received from Google'); return NextResponse.json( - { - success: false, - message: 'No id_token received from Google' - }, - { status: 400 } + { + success: false, + message: 'No id_token received from Google' + }, + { status: 400 } ); } - // 第二步:使用id_token调用smartvideo-server的register_with_invite接口 - const smartvideoBaseUrl = process.env.NEXT_PUBLIC_SMARTVIDEO_URL; - console.log('开始调用smartvideo-server后端:', smartvideoBaseUrl); - - // 从Google ID Token中解析用户信息(简单解析,仅用于获取email等基本信息) - let googleUserInfo: any = {}; - try { - // 解码Google ID Token的payload部分(注意:这里只是为了获取基本信息,真正的验证在后端进行) - const tokenParts = id_token.split('.'); - if (tokenParts.length === 3) { - const payload = JSON.parse(atob(tokenParts[1])); - googleUserInfo = { - email: payload.email, - name: payload.name, - given_name: payload.given_name, - family_name: payload.family_name - }; - } - } catch (e) { - console.warn('解析Google ID Token失败,使用空的用户信息:', e); - } - - const backendResponse = await fetch(`${smartvideoBaseUrl}/api/user_fission/register_with_invite`, { + // 第二步:使用id_token调用Java后端 + const javaBaseUrl = process.env.NEXT_PUBLIC_JAVA_URL || 'https://auth.test.movieflow.ai'; + console.log('开始调用Java后端:', javaBaseUrl); + + const backendResponse = await fetch(`${javaBaseUrl}/api/auth/google/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ - email: googleUserInfo.email, // 从Google Token中获取的邮箱 - name: googleUserInfo.name, // 从Google Token中获取的姓名 - google_id_token: id_token, // Google ID Token - auth_type: 'GOOGLE', // 标识为Google OAuth注册 - invite_code: inviteCode || stateData.inviteCode || undefined + idToken: id_token, // 使用从Google获取的id_token + action: 'auto', // 自动判断登录或注册 + inviteCode: inviteCode || stateData.inviteCode || undefined }) }); - console.log('smartvideo-server后端响应状态:', backendResponse.status); + console.log('Java后端响应状态:', backendResponse.status); const backendResult = await backendResponse.json(); - if (!backendResponse.ok || !backendResult.successful) { - console.error('smartvideo-server处理Google OAuth失败:', backendResult); + if (!backendResponse.ok || !backendResult.success) { + console.error('Java后端处理Google OAuth失败:', backendResult); return NextResponse.json( - { - success: false, - message: backendResult.message || 'Google authentication failed' - }, - { status: backendResponse.status || 500 } + { + success: false, + message: backendResult.message || 'Google authentication failed' + }, + { status: backendResponse.status || 500 } ); } console.log('Google OAuth认证成功:', { - userId: backendResult.data?.user_id, - email: backendResult.data?.email + userId: backendResult.data?.user?.userId, + email: backendResult.data?.user?.email }); - // 返回成功结果,格式与原有保持一致以确保前端兼容性 + // 返回成功结果 return NextResponse.json({ success: true, data: { - // 包含token以支持前端认证 token: backendResult.data.token, - user: { - userId: backendResult.data.user_id, - userName: backendResult.data.name, - name: backendResult.data.name, - email: backendResult.data.email, - authType: backendResult.data.auth_type, - isNewUser: true // 通过register_with_invite接口的都是新用户或首次OAuth绑定 - }, - message: 'Google OAuth registration successful with credit rewards' + user: backendResult.data.userInfo || backendResult.data.user, + message: 'Google authentication successful' } }); } 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 } + { + success: false, + message: 'Backend service unavailable. Please try again later.' + }, + { status: 503 } ); } - + return NextResponse.json( - { - success: false, - message: error.message || 'Internal server error during Google OAuth callback' - }, - { status: 500 } + { + success: false, + message: error.message || 'Internal server error during Google OAuth callback' + }, + { status: 500 } ); } } @@ -273,7 +245,7 @@ export async function POST(request: NextRequest) { */ function getRedirectUri(request: NextRequest): string { const host = request.headers.get('host') || ''; - + if (host.includes('localhost') || host.includes('127.0.0.1')) { // 本地开发环境:使用实际的端口号(可能是3000或3001) const protocol = 'http'; @@ -296,30 +268,30 @@ export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url); const code = searchParams.get('code'); const state = searchParams.get('state'); - + if (!code || !state) { return NextResponse.json( - { - success: false, - message: 'Missing required parameters: code and state' - }, - { status: 400 } + { + success: false, + message: 'Missing required parameters: code and state' + }, + { status: 400 } ); } - + // 重定向到页面路由,让页面处理OAuth回调 const callbackUrl = `/users/oauth/callback?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`; - + // 修复:确保使用正确的域名进行重定向 const host = request.headers.get('host') || 'www.movieflow.net'; const protocol = request.headers.get('x-forwarded-proto') || 'https'; const fullCallbackUrl = `${protocol}://${host}${callbackUrl}`; - + console.log('🔍 前端API重定向调试:'); console.log(' - request.url:', request.url); console.log(' - host header:', host); console.log(' - protocol:', protocol); console.log(' - 重定向到:', fullCallbackUrl); - + return NextResponse.redirect(fullCallbackUrl); }