fix: enhance OAuth configuration and add debugging - Add Google OAuth authorization parameters - Add environment variable validation - Add debugging logs for redirect callback - Create OAuth configuration check script

This commit is contained in:
theshy
2025-08-01 20:42:03 +08:00
parent 2cd0ebda65
commit e955f4c317
8 changed files with 195 additions and 358 deletions

View File

@ -7,42 +7,31 @@ import CredentialsProvider from "next-auth/providers/credentials";
import { UserService } from "./services/user.service";
import { AuthOptions } from "next-auth";
// 验证和清理 NEXTAUTH_URL
function getValidatedNextAuthUrl(): string {
const url = process.env.NEXTAUTH_URL;
if (!url) {
throw new Error("NEXTAUTH_URL 环境变量未设置");
}
// 验证环境变量
function validateAuthConfig() {
const requiredEnvVars = [
'GOOGLE_CLIENT_ID',
'GOOGLE_CLIENT_SECRET',
'NEXTAUTH_SECRET',
'NEXTAUTH_URL'
];
const missingVars = requiredEnvVars.filter(varName => !process.env[varName]);
// 清理 URL移除多余的引号
let cleanUrl = url.trim();
if (cleanUrl.startsWith('"') && cleanUrl.endsWith('"')) {
cleanUrl = cleanUrl.slice(1, -1);
if (missingVars.length > 0) {
console.error('Missing required environment variables:', missingVars);
throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
}
if (cleanUrl.startsWith("'") && cleanUrl.endsWith("'")) {
cleanUrl = cleanUrl.slice(1, -1);
}
// 确保 URL 格式正确
try {
new URL(cleanUrl);
} catch (error) {
throw new Error(`无效的 NEXTAUTH_URL: ${cleanUrl}`);
}
return cleanUrl;
console.log('Auth configuration validated:', {
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID?.substring(0, 20) + '...',
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET ? 'Set' : 'Missing'
});
}
// 获取域名用于 Cookie 配置
function getDomain(): string {
const url = getValidatedNextAuthUrl();
try {
const urlObj = new URL(url);
return urlObj.hostname;
} catch {
return "recorder.zyj.best"; // 默认域名
}
}
// 验证配置
validateAuthConfig();
export const authOptions: AuthOptions = {
adapter: PrismaAdapter(prisma),
@ -51,6 +40,13 @@ export const authOptions: AuthOptions = {
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code"
}
}
}),
CredentialsProvider({
@ -117,10 +113,22 @@ export const authOptions: AuthOptions = {
},
async redirect({ url, baseUrl }) {
// 调试信息
console.log("Redirect callback:", { url, baseUrl });
// 确保重定向到正确的页面
if (url.startsWith("/")) return `${baseUrl}${url}`;
else if (new URL(url).origin === baseUrl) return url;
return `${baseUrl}/dashboard`;
if (url.startsWith("/")) {
const redirectUrl = `${baseUrl}${url}`;
console.log("Redirecting to:", redirectUrl);
return redirectUrl;
} else if (new URL(url).origin === baseUrl) {
console.log("Redirecting to same origin:", url);
return url;
}
const defaultUrl = `${baseUrl}/dashboard`;
console.log("Redirecting to default:", defaultUrl);
return defaultUrl;
},
},
@ -131,69 +139,4 @@ export const authOptions: AuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
debug: process.env.NODE_ENV === "development",
// 添加 Cookie 配置
cookies: {
sessionToken: {
name: `next-auth.session-token`,
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
secure: process.env.NODE_ENV === "production",
domain: process.env.NODE_ENV === "production" ? getDomain() : undefined,
},
},
callbackUrl: {
name: `next-auth.callback-url`,
options: {
sameSite: "lax",
path: "/",
secure: process.env.NODE_ENV === "production",
domain: process.env.NODE_ENV === "production" ? getDomain() : undefined,
},
},
csrfToken: {
name: `next-auth.csrf-token`,
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
secure: process.env.NODE_ENV === "production",
domain: process.env.NODE_ENV === "production" ? getDomain() : undefined,
},
},
pkceCodeVerifier: {
name: `next-auth.pkce.code_verifier`,
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
maxAge: 900,
secure: process.env.NODE_ENV === "production",
domain: process.env.NODE_ENV === "production" ? getDomain() : undefined,
},
},
state: {
name: `next-auth.state`,
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
maxAge: 900,
secure: process.env.NODE_ENV === "production",
domain: process.env.NODE_ENV === "production" ? getDomain() : undefined,
},
},
nonce: {
name: `next-auth.nonce`,
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
secure: process.env.NODE_ENV === "production",
domain: process.env.NODE_ENV === "production" ? getDomain() : undefined,
},
},
},
};