forked from 77media/video-flow
谷歌登录回调
This commit is contained in:
parent
b2e8dfb86f
commit
26ce68bd54
@ -1,175 +1,10 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
import type { OAuthCallbackParams } from '@/app/types/google-oauth';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Google OAuth回调处理API
|
* Google OAuth回调处理API
|
||||||
* 处理从Google OAuth返回的授权码,完成用户认证
|
* 注意:POST 方法已废弃,业务逻辑已移至 /users/oauth/callback 页面
|
||||||
|
* 此文件现在仅用于处理 Google 的 GET 回调重定向
|
||||||
*/
|
*/
|
||||||
export async function POST(request: NextRequest) {
|
|
||||||
console.log('🎯 Google OAuth Callback API 被调用');
|
|
||||||
console.log('📍 Request URL:', request.url);
|
|
||||||
console.log('📍 Request method:', request.method);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
console.log('📦 Request body:', body);
|
|
||||||
const { code, state, inviteCode } = body;
|
|
||||||
|
|
||||||
// 验证必需参数
|
|
||||||
if (!code || !state) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{
|
|
||||||
success: false,
|
|
||||||
message: 'Missing required parameters: code and state'
|
|
||||||
},
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移除开发模式模拟,始终调用真实接口
|
|
||||||
console.log('🚀 开始处理Google OAuth回调,调用真实接口');
|
|
||||||
|
|
||||||
// 解析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 = 'https://auth.test.movieflow.ai';
|
|
||||||
console.log('🔧 使用固定的 javaBaseUrl:', javaBaseUrl);
|
|
||||||
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
|
* 根据请求获取正确的redirect_uri
|
||||||
|
|||||||
@ -78,58 +78,126 @@ export default function OAuthCallback() {
|
|||||||
console.log('State数据:', stateData);
|
console.log('State数据:', stateData);
|
||||||
console.log('最终使用的邀请码:', finalInviteCode);
|
console.log('最终使用的邀请码:', finalInviteCode);
|
||||||
|
|
||||||
// 调用Next.js API路由处理授权码(新的两步流程:Java验证 + Python注册)
|
// 直接处理 OAuth 回调(两步流程:Java验证 + Python注册)
|
||||||
console.log('调用Next.js API路由:', '/api/auth/google/callback');
|
console.log('开始直接处理 OAuth 回调,无需经过 API 路由');
|
||||||
|
|
||||||
const response = await fetch('/api/auth/google/callback', {
|
// 第一步:调用Java验证接口(只验证不创建用户)
|
||||||
|
const javaBaseUrl = 'https://auth.test.movieflow.ai';
|
||||||
|
console.log('🔧 调用 Java 验证接口:', javaBaseUrl);
|
||||||
|
|
||||||
|
const verifyResponse = await fetch(`${javaBaseUrl}/api/auth/google/callback`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
code: params.code,
|
code: params.code, // Google authorization code
|
||||||
state: params.state,
|
state: params.state, // state参数
|
||||||
...(finalInviteCode && { inviteCode: finalInviteCode })
|
inviteCode: finalInviteCode, // 邀请码
|
||||||
|
skipUserCreation: true // 🔑 关键:只验证不创建用户
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
console.log('Java验证接口响应状态:', verifyResponse.status);
|
||||||
// 处理HTTP错误状态
|
const verifyResult = await verifyResponse.json();
|
||||||
const errorText = await response.text();
|
|
||||||
console.error('OAuth API调用失败:', response.status, errorText);
|
if (!verifyResponse.ok || !verifyResult.success) {
|
||||||
throw new Error(`OAuth API调用失败 (${response.status}): ${errorText}`);
|
console.error('Java验证接口处理失败:', verifyResult);
|
||||||
|
throw new Error(verifyResult.message || 'Google token verification failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
console.log('Google Token验证成功:', {
|
||||||
console.log('OAuth API响应:', result);
|
email: verifyResult.data?.email,
|
||||||
|
name: verifyResult.data?.name
|
||||||
|
});
|
||||||
|
|
||||||
if (result.success) {
|
// 第二步:调用Python注册接口进行用户创建和积分发放
|
||||||
console.log('Google登录成功:', result);
|
const smartvideoBaseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'https://77.smartvideo.py.qikongjian.com';
|
||||||
setStatus("success");
|
console.log('🔧 调用 Python 注册接口:', smartvideoBaseUrl);
|
||||||
setMessage("Login successful! Redirecting to dashboard...");
|
|
||||||
|
|
||||||
// 保存用户信息到localStorage (使用认证库的统一键名)
|
const registerResponse = await fetch(`${smartvideoBaseUrl}/api/user_fission/register_with_invite`, {
|
||||||
if (result.data?.user) {
|
method: 'POST',
|
||||||
localStorage.setItem('currentUser', JSON.stringify(result.data.user));
|
headers: {
|
||||||
}
|
'Content-Type': 'application/json',
|
||||||
if (result.data?.token) {
|
'Accept': 'application/json',
|
||||||
localStorage.setItem('token', result.data.token);
|
},
|
||||||
}
|
body: JSON.stringify({
|
||||||
|
email: verifyResult.data.email,
|
||||||
|
name: verifyResult.data.name,
|
||||||
|
auth_type: 'GOOGLE',
|
||||||
|
google_user_info: {
|
||||||
|
email: verifyResult.data.email,
|
||||||
|
name: verifyResult.data.name,
|
||||||
|
picture: verifyResult.data.picture || '',
|
||||||
|
googleId: verifyResult.data.googleId || verifyResult.data.id || '',
|
||||||
|
verified: verifyResult.data.verified || true,
|
||||||
|
inviteCode: finalInviteCode
|
||||||
|
},
|
||||||
|
invite_code: finalInviteCode
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
// 2秒后跳转到主页
|
console.log('Python注册接口响应状态:', registerResponse.status);
|
||||||
setTimeout(() => {
|
const registerResult = await registerResponse.json();
|
||||||
// 修复: Google登录成功后应该跳转到主页面,而不是来源页面
|
|
||||||
const returnUrl = '/movies';
|
if (!registerResponse.ok || !registerResult.successful) {
|
||||||
window.location.href = returnUrl;
|
console.error('Python注册接口处理失败:', registerResult);
|
||||||
}, 2000);
|
throw new Error(registerResult.message || 'User registration failed');
|
||||||
} else {
|
|
||||||
throw new Error(result.message || 'Google登录失败');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Google OAuth注册成功:', {
|
||||||
|
userId: registerResult.data?.user_id,
|
||||||
|
email: registerResult.data?.email
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理成功结果
|
||||||
|
console.log('Google登录成功:', registerResult);
|
||||||
|
setStatus("success");
|
||||||
|
setMessage("Login successful! Redirecting to dashboard...");
|
||||||
|
|
||||||
|
// 保存用户信息到localStorage
|
||||||
|
const userData = {
|
||||||
|
userId: registerResult.data.user_id,
|
||||||
|
userName: registerResult.data.name,
|
||||||
|
name: registerResult.data.name,
|
||||||
|
email: registerResult.data.email,
|
||||||
|
authType: registerResult.data.auth_type || 'GOOGLE',
|
||||||
|
isNewUser: true,
|
||||||
|
inviteCode: registerResult.data.invite_code
|
||||||
|
};
|
||||||
|
|
||||||
|
localStorage.setItem('currentUser', JSON.stringify(userData));
|
||||||
|
if (registerResult.data.token) {
|
||||||
|
localStorage.setItem('token', registerResult.data.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2秒后跳转到主页
|
||||||
|
setTimeout(() => {
|
||||||
|
const returnUrl = '/movies';
|
||||||
|
window.location.href = returnUrl;
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("OAuth callback error:", error);
|
console.error("OAuth callback error:", error);
|
||||||
|
|
||||||
|
// 检查是否是网络连接错误
|
||||||
|
if (error.code === 'ECONNREFUSED' || error.message?.includes('fetch failed')) {
|
||||||
|
console.error('网络连接失败,可能是后端服务不可用');
|
||||||
|
setStatus("error");
|
||||||
|
setMessage('Backend service unavailable. Please try again later.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是 JSON 解析错误
|
||||||
|
if (error.message?.includes('JSON') || error.name === 'SyntaxError') {
|
||||||
|
console.error('响应数据解析失败:', error);
|
||||||
|
setStatus("error");
|
||||||
|
setMessage('Invalid response format from backend services');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理邮箱冲突错误
|
||||||
if (error.type === 'EMAIL_CONFLICT') {
|
if (error.type === 'EMAIL_CONFLICT') {
|
||||||
setStatus("conflict");
|
setStatus("conflict");
|
||||||
setMessage(error.message);
|
setMessage(error.message);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user