优化认证和中间件功能

This commit is contained in:
Your Name 2025-12-25 23:08:33 +08:00
parent 712041bbeb
commit 9076b4ab15
8 changed files with 135 additions and 23 deletions

View File

@ -99,7 +99,11 @@ export default function Page() {
if (session && session.user) {
console.log("[DingTalk] Session validated, redirecting to home...");
setIsSuccessful(true);
window.location.replace("/");
// 使用 replace 而不是 href,避免在历史记录中留下登录页
// 增加短暂延迟确保 cookie 完全同步
setTimeout(() => {
window.location.replace("/");
}, 200);
} else {
console.error("[DingTalk] Session not created after login");
setIsHandlingToken(false);
@ -124,7 +128,11 @@ export default function Page() {
if (session && session.user) {
console.log("[DingTalk] Session validated, redirecting...");
setIsSuccessful(true);
window.location.replace(result.url || "/");
// 使用 replace 而不是 href,避免在历史记录中留下登录页
// 增加短暂延迟确保 cookie 完全同步
setTimeout(() => {
window.location.replace(result.url || "/");
}, 200);
} else {
console.error("[DingTalk] Session not created");
setIsHandlingToken(false);
@ -176,8 +184,8 @@ export default function Page() {
console.log("🔔 登录页面代码版本: 2024-12-10 v3.0");
console.log("=".repeat(50));
// 获取网站设置
fetch("/api/site-settings")
// 获取网站设置(添加时间戳防止缓存)
fetch(`/api/site-settings?t=${Date.now()}`)
.then((res) => res.json())
.then((data) => {
console.log("[Login] Site settings data:", data);

View File

@ -29,8 +29,8 @@ export default function Page() {
})
.catch(console.error);
// 获取网站设置
fetch("/api/site-settings")
// 获取网站设置(添加时间戳防止缓存)
fetch(`/api/site-settings?t=${Date.now()}`)
.then((res) => res.json())
.then((data) => {
if (data.siteName) setSiteName(data.siteName);

View File

@ -27,11 +27,12 @@ async function ChatPage({ params }: { params: Promise<{ id: string }> }) {
const session = await auth();
if (chat.visibility === "private") {
if (!session?.user) {
return notFound();
}
// 如果用户未登录,重定向到登录页面
if (!session?.user) {
redirect("/login");
}
if (chat.visibility === "private") {
if (session.user.id !== chat.userId) {
return notFound();
}

View File

@ -1,4 +1,5 @@
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
import { Suspense } from "react";
import { Chat } from "@/components/chat";
import { DataStreamHandler } from "@/components/data-stream-handler";
@ -18,6 +19,12 @@ async function NewChatPage() {
const id = generateUUID();
const [session, cookieStore] = await Promise.all([auth(), cookies()]);
// 如果用户未登录,重定向到登录页面
if (!session?.user) {
redirect("/login");
}
const modelIdFromCookie = cookieStore.get("chat-model");
// 如果没有保存的模型 ID,从数据库获取默认模型

View File

@ -32,10 +32,17 @@ export async function GET() {
usageTimeMessage: "由壹点累了也是需要休息的",
};
return NextResponse.json({
const response = NextResponse.json({
...baseSettings,
notification,
});
// 禁用缓存,确保总是获取最新设置
response.headers.set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");
response.headers.set("Pragma", "no-cache");
response.headers.set("Expires", "0");
return response;
} catch (error) {
console.error("[Site Settings API] Get error:", error);
return NextResponse.json(

65
middleware.ts Normal file
View File

@ -0,0 +1,65 @@
import { type NextRequest, NextResponse } from "next/server";
import { getToken } from "next-auth/jwt";
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 允许访问 ping 端点
if (pathname.startsWith("/ping")) {
return NextResponse.next();
}
// 允许访问认证相关 API
if (pathname.startsWith("/api/auth")) {
return NextResponse.next();
}
// 允许访问钉钉回调页面(public 文件夹中的文件)
if (pathname === "/dingtalk-callback.html") {
return NextResponse.next();
}
// 检测是否为 HTTPS(通过 AUTH_URL 或请求协议判断)
const isSecure = process.env.AUTH_URL?.startsWith("https://") ||
request.nextUrl.protocol === "https:";
const token = await getToken({
req: request,
secret: process.env.AUTH_SECRET,
secureCookie: isSecure,
});
const externalBase =
process.env.AUTH_URL ??
`${request.nextUrl.protocol}//${request.headers.get("host") ?? request.nextUrl.host}`;
// 未登录用户只能访问 /login 和 /register
if (!token && !["/login", "/register"].includes(pathname)) {
const loginUrl = new URL("/login", externalBase);
// 保存当前路径作为回调 URL
loginUrl.searchParams.set("callbackUrl", pathname);
return NextResponse.redirect(loginUrl);
}
// 已登录用户访问 /login 或 /register 时重定向到首页
if (token && ["/login", "/register"].includes(pathname)) {
return NextResponse.redirect(new URL("/", externalBase));
}
return NextResponse.next();
}
export const config = {
matcher: [
/*
* 匹配所有请求路径,除了:
* - api/auth (NextAuth.js)
* - _next/static (静态文件)
* - _next/image (图片优化文件)
* - favicon.ico (favicon文件)
* - public 文件夹中的文件
*/
"/((?!api/auth|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
],
};

View File

@ -168,20 +168,43 @@
statusText.textContent = '登录成功,正在跳转...';
console.log('[DingTalk Callback] Login successful, redirecting to home...');
// 等待一小段时间确保 cookie 被设置
await new Promise(resolve => setTimeout(resolve, 300));
// 等待更长时间确保 cookie 被设置并同步
await new Promise(resolve => setTimeout(resolve, 800));
// 使用 window.top.location 确保跳转整个页面(即使在 iframe 中)
try {
if (window.top && window.top.location) {
window.top.location.href = '/';
} else {
window.location.href = '/';
// 验证 session 是否已创建
const sessionRes = await fetch('/api/auth/session', {
credentials: 'include'
});
const session = await sessionRes.json();
console.log('[DingTalk Callback] Session after login:', session);
if (session && session.user) {
console.log('[DingTalk Callback] Session validated, redirecting...');
// 使用 window.top.location 确保跳转整个页面(即使在 iframe 中)
try {
if (window.top && window.top.location) {
window.top.location.replace('/');
} else {
window.location.replace('/');
}
} catch (e) {
// 如果跨域阻止,使用当前窗口跳转
console.warn('[DingTalk Callback] Cross-origin blocked, using current window');
window.location.replace('/');
}
} else {
console.error('[DingTalk Callback] Session not created, retrying...');
// 如果 session 还未创建,再等待一段时间后重试
await new Promise(resolve => setTimeout(resolve, 500));
const retrySessionRes = await fetch('/api/auth/session', {
credentials: 'include'
});
const retrySession = await retrySessionRes.json();
if (retrySession && retrySession.user) {
window.location.replace('/');
} else {
throw new Error('登录失败:无法创建会话,请刷新页面重试');
}
} catch (e) {
// 如果跨域阻止,使用当前窗口跳转
console.warn('[DingTalk Callback] Cross-origin blocked, using current window');
window.location.href = '/';
}
} else {
const result = await loginRes.json();

View File

@ -524,3 +524,4 @@ curl http://localhost:8002/health