forked from 77media/video-flow
264 lines
8.4 KiB
TypeScript
264 lines
8.4 KiB
TypeScript
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);
|
||
}
|