2025-09-22 22:09:49 +08:00

264 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from 'next/server';
import type { OAuthCallbackParams } from '@/app/types/google-oauth';
/**
* Google OAuth回调处理API
* 处理从Google OAuth返回的授权码完成用户认证
*/
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { code, state, inviteCode } = body;
// 验证必需参数
if (!code || !state) {
return NextResponse.json(
{
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 {
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 {
stateData = JSON.parse(state);
} catch (e) {
console.warn('无法解析state参数:', state);
return NextResponse.json(
{
success: false,
message: 'Invalid state parameter'
},
{ status: 400 }
);
}
console.log('Google OAuth回调处理开始:', {
codeLength: code.length,
stateData,
inviteCode
});
// 直接将authorization code传递给Java后端处理
console.log('准备调用Java后端验证Google authorization code...');
// 第二步调用Java验证接口只验证不创建用户
const javaBaseUrl = process.env.NEXT_PUBLIC_JAVA_URL || 'https://auth.test.movieflow.ai';
console.log('开始调用Java验证接口:', javaBaseUrl);
const verifyResponse = await fetch(`${javaBaseUrl}/api/auth/google/callback`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
code: code, // Google authorization code
state: state, // state参数
inviteCode: inviteCode || stateData.inviteCode || undefined,
skipUserCreation: true // 🔑 关键:只验证不创建用户
})
});
console.log('Java验证接口响应状态:', verifyResponse.status);
const verifyResult = await verifyResponse.json();
if (!verifyResponse.ok || !verifyResult.success) {
console.error('Java验证接口处理失败:', verifyResult);
return NextResponse.json(
{
success: false,
message: verifyResult.message || 'Google token verification failed'
},
{ status: verifyResponse.status || 500 }
);
}
console.log('Google Token验证成功:', {
email: verifyResult.data?.email,
name: verifyResult.data?.name
});
// 第三步调用Python注册接口进行用户创建和积分发放
const smartvideoBaseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'https://77.smartvideo.py.qikongjian.com';
console.log('开始调用Python注册接口:', smartvideoBaseUrl);
const registerResponse = await fetch(`${smartvideoBaseUrl}/api/user_fission/register_with_invite`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
email: verifyResult.data.email,
name: verifyResult.data.name,
auth_type: 'GOOGLE',
google_user_info: verifyResult.data,
invite_code: inviteCode || stateData.inviteCode || undefined
})
});
console.log('Python注册接口响应状态:', registerResponse.status);
const registerResult = await registerResponse.json();
if (!registerResponse.ok || !registerResult.successful) {
console.error('Python注册接口处理失败:', registerResult);
return NextResponse.json(
{
success: false,
message: registerResult.message || 'User registration failed'
},
{ status: registerResponse.status || 500 }
);
}
console.log('Google OAuth注册成功:', {
userId: registerResult.data?.user_id,
email: registerResult.data?.email
});
// 返回成功结果(统一格式)
return NextResponse.json({
success: true,
data: {
token: registerResult.data.token,
user: {
userId: registerResult.data.user_id,
userName: registerResult.data.name,
name: registerResult.data.name,
email: registerResult.data.email,
authType: registerResult.data.auth_type,
isNewUser: true
},
message: 'Google OAuth registration successful with credit rewards'
}
});
} 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,
message: error.message || 'Internal server error during Google OAuth callback'
},
{ status: 500 }
);
}
}
/**
* 根据请求获取正确的redirect_uri
*/
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';
return `${protocol}://${host}/api/auth/google/callback`;
} else if (host.includes('movieflow.net')) {
return 'https://www.movieflow.net/api/auth/google/callback';
} else if (host.includes('movieflow.ai')) {
return 'https://www.movieflow.ai/api/auth/google/callback';
} else {
// 默认使用生产环境
return 'https://www.movieflow.ai/api/auth/google/callback';
}
}
/**
* 处理GET请求 - Google OAuth回调
* 将GET请求重定向到页面路由进行处理
*/
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 }
);
}
// 重定向到页面路由让页面处理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);
}