优化认证和中间件功能
This commit is contained in:
parent
712041bbeb
commit
9076b4ab15
@ -99,7 +99,11 @@ export default function Page() {
|
|||||||
if (session && session.user) {
|
if (session && session.user) {
|
||||||
console.log("[DingTalk] Session validated, redirecting to home...");
|
console.log("[DingTalk] Session validated, redirecting to home...");
|
||||||
setIsSuccessful(true);
|
setIsSuccessful(true);
|
||||||
window.location.replace("/");
|
// 使用 replace 而不是 href,避免在历史记录中留下登录页
|
||||||
|
// 增加短暂延迟确保 cookie 完全同步
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.replace("/");
|
||||||
|
}, 200);
|
||||||
} else {
|
} else {
|
||||||
console.error("[DingTalk] Session not created after login");
|
console.error("[DingTalk] Session not created after login");
|
||||||
setIsHandlingToken(false);
|
setIsHandlingToken(false);
|
||||||
@ -124,7 +128,11 @@ export default function Page() {
|
|||||||
if (session && session.user) {
|
if (session && session.user) {
|
||||||
console.log("[DingTalk] Session validated, redirecting...");
|
console.log("[DingTalk] Session validated, redirecting...");
|
||||||
setIsSuccessful(true);
|
setIsSuccessful(true);
|
||||||
window.location.replace(result.url || "/");
|
// 使用 replace 而不是 href,避免在历史记录中留下登录页
|
||||||
|
// 增加短暂延迟确保 cookie 完全同步
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.replace(result.url || "/");
|
||||||
|
}, 200);
|
||||||
} else {
|
} else {
|
||||||
console.error("[DingTalk] Session not created");
|
console.error("[DingTalk] Session not created");
|
||||||
setIsHandlingToken(false);
|
setIsHandlingToken(false);
|
||||||
@ -176,8 +184,8 @@ export default function Page() {
|
|||||||
console.log("🔔 登录页面代码版本: 2024-12-10 v3.0");
|
console.log("🔔 登录页面代码版本: 2024-12-10 v3.0");
|
||||||
console.log("=".repeat(50));
|
console.log("=".repeat(50));
|
||||||
|
|
||||||
// 获取网站设置
|
// 获取网站设置(添加时间戳防止缓存)
|
||||||
fetch("/api/site-settings")
|
fetch(`/api/site-settings?t=${Date.now()}`)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log("[Login] Site settings data:", data);
|
console.log("[Login] Site settings data:", data);
|
||||||
|
|||||||
@ -29,8 +29,8 @@ export default function Page() {
|
|||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
|
|
||||||
// 获取网站设置
|
// 获取网站设置(添加时间戳防止缓存)
|
||||||
fetch("/api/site-settings")
|
fetch(`/api/site-settings?t=${Date.now()}`)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.siteName) setSiteName(data.siteName);
|
if (data.siteName) setSiteName(data.siteName);
|
||||||
|
|||||||
@ -27,11 +27,12 @@ async function ChatPage({ params }: { params: Promise<{ id: string }> }) {
|
|||||||
|
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
|
|
||||||
if (chat.visibility === "private") {
|
// 如果用户未登录,重定向到登录页面
|
||||||
if (!session?.user) {
|
if (!session?.user) {
|
||||||
return notFound();
|
redirect("/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chat.visibility === "private") {
|
||||||
if (session.user.id !== chat.userId) {
|
if (session.user.id !== chat.userId) {
|
||||||
return notFound();
|
return notFound();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { Chat } from "@/components/chat";
|
import { Chat } from "@/components/chat";
|
||||||
import { DataStreamHandler } from "@/components/data-stream-handler";
|
import { DataStreamHandler } from "@/components/data-stream-handler";
|
||||||
@ -18,6 +19,12 @@ async function NewChatPage() {
|
|||||||
const id = generateUUID();
|
const id = generateUUID();
|
||||||
|
|
||||||
const [session, cookieStore] = await Promise.all([auth(), cookies()]);
|
const [session, cookieStore] = await Promise.all([auth(), cookies()]);
|
||||||
|
|
||||||
|
// 如果用户未登录,重定向到登录页面
|
||||||
|
if (!session?.user) {
|
||||||
|
redirect("/login");
|
||||||
|
}
|
||||||
|
|
||||||
const modelIdFromCookie = cookieStore.get("chat-model");
|
const modelIdFromCookie = cookieStore.get("chat-model");
|
||||||
|
|
||||||
// 如果没有保存的模型 ID,从数据库获取默认模型
|
// 如果没有保存的模型 ID,从数据库获取默认模型
|
||||||
|
|||||||
@ -32,10 +32,17 @@ export async function GET() {
|
|||||||
usageTimeMessage: "由壹点累了也是需要休息的",
|
usageTimeMessage: "由壹点累了也是需要休息的",
|
||||||
};
|
};
|
||||||
|
|
||||||
return NextResponse.json({
|
const response = NextResponse.json({
|
||||||
...baseSettings,
|
...baseSettings,
|
||||||
notification,
|
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) {
|
} catch (error) {
|
||||||
console.error("[Site Settings API] Get error:", error);
|
console.error("[Site Settings API] Get error:", error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
65
middleware.ts
Normal file
65
middleware.ts
Normal 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)$).*)",
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
@ -168,20 +168,43 @@
|
|||||||
statusText.textContent = '登录成功,正在跳转...';
|
statusText.textContent = '登录成功,正在跳转...';
|
||||||
console.log('[DingTalk Callback] Login successful, redirecting to home...');
|
console.log('[DingTalk Callback] Login successful, redirecting to home...');
|
||||||
|
|
||||||
// 等待一小段时间确保 cookie 被设置
|
// 等待更长时间确保 cookie 被设置并同步
|
||||||
await new Promise(resolve => setTimeout(resolve, 300));
|
await new Promise(resolve => setTimeout(resolve, 800));
|
||||||
|
|
||||||
// 使用 window.top.location 确保跳转整个页面(即使在 iframe 中)
|
// 验证 session 是否已创建
|
||||||
try {
|
const sessionRes = await fetch('/api/auth/session', {
|
||||||
if (window.top && window.top.location) {
|
credentials: 'include'
|
||||||
window.top.location.href = '/';
|
});
|
||||||
} else {
|
const session = await sessionRes.json();
|
||||||
window.location.href = '/';
|
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 {
|
} else {
|
||||||
const result = await loginRes.json();
|
const result = await loginRes.json();
|
||||||
|
|||||||
@ -524,3 +524,4 @@ curl http://localhost:8002/health
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user