diff --git a/crop-x/src/app/layout.tsx b/crop-x/src/app/layout.tsx
index 860741e..d950d9e 100644
--- a/crop-x/src/app/layout.tsx
+++ b/crop-x/src/app/layout.tsx
@@ -2,6 +2,7 @@
import { useEffect } from 'react';
import { AuthProvider } from '@/components/auth/AuthContext';
+import { ClientAuthInterceptor } from '@/components/auth/ClientAuthInterceptor';
export default function AppLayout({
children,
@@ -14,10 +15,12 @@ export default function AppLayout({
}, []);
return (
-
+
- {children}
+
+ {children}
+
diff --git a/crop-x/src/components/auth/ClientAuthInterceptor.tsx b/crop-x/src/components/auth/ClientAuthInterceptor.tsx
new file mode 100644
index 0000000..546d759
--- /dev/null
+++ b/crop-x/src/components/auth/ClientAuthInterceptor.tsx
@@ -0,0 +1,75 @@
+'use client';
+
+import { useEffect } from 'react';
+import { useRouter } from 'next/navigation';
+import { useAuth } from './AuthContext';
+
+interface ClientAuthInterceptorProps {
+ children: React.ReactNode;
+}
+
+export function ClientAuthInterceptor({ children }: ClientAuthInterceptorProps) {
+ const { user, isAuthenticated, loading } = useAuth();
+ const router = useRouter();
+
+ useEffect(() => {
+ // 如果正在加载,等待加载完成
+ if (loading) {
+ return;
+ }
+
+ const currentPath = window.location.pathname;
+
+ // 如果已经在登录页面,不需要重定向
+ if (currentPath === '/login' || currentPath === '/register') {
+ console.log(`📄 已在认证页面,跳过拦截: ${currentPath}`);
+ return;
+ }
+
+ // 如果未认证,重定向到登录页
+ if (!isAuthenticated) {
+ console.log(`🔒 客户端拦截:未认证用户访问 ${currentPath},重定向到登录页`);
+
+ // 保存当前路径,登录后可以跳转回来
+ const loginUrl = `/login${currentPath !== '/' ? `?redirect=${encodeURIComponent(currentPath)}` : ''}`;
+ router.push(loginUrl);
+ return;
+ }
+
+ console.log(`✅ 客户端认证通过:用户 ${user?.username} 访问 ${window.location.pathname}`);
+ }, [isAuthenticated, loading, user, router]);
+
+ const currentPath = typeof window !== 'undefined' ? window.location.pathname : '';
+
+ // 如果正在加载,显示加载状态
+ if (loading) {
+ return (
+
+ );
+ }
+
+ // 如果在认证页面(登录/注册),直接渲染子组件,不需要认证检查
+ if (currentPath === '/login' || currentPath === '/register') {
+ return <>{children}>;
+ }
+
+ // 如果未认证且不在认证页面,显示跳转状态
+ if (!isAuthenticated) {
+ return (
+
+ );
+ }
+
+ // 认证通过,渲染子组件
+ return <>{children}>;
+}
\ No newline at end of file
diff --git a/crop-x/src/middleware.ts b/crop-x/src/middleware.ts
deleted file mode 100644
index 50d8abb..0000000
--- a/crop-x/src/middleware.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { NextResponse } from "next/server";
-
-// 定义不需要认证的路径
-const publicPaths = [
- "/login",
- "/register",
- "/api",
- "/_next",
- "/favicon.ico",
- "/static"
-];
-
-export async function middleware(request: any) {
- const { pathname } = request.nextUrl;
-
- console.log(`🔍 中间件拦截路径: ${pathname}`);
-
- // 检查是否是公开路径
- if (publicPaths.some(path => pathname.startsWith(path))) {
- console.log(`✅ 公开路径,允许访问: ${pathname}`);
- return NextResponse.next();
- }
-
- try {
- // 从 cookie 中获取 token
- const token = request.cookies.get("auth-token")?.value;
-
- console.log(`🍪 Cookie中的token状态: ${token ? '存在' : '不存在'}`);
-
- // 如果没有 token,重定向到登录页
- if (!token) {
- console.log(`🔒 未找到认证 token,重定向到登录页: ${pathname}`);
- const loginUrl = new URL("/login", request.url);
- loginUrl.searchParams.set("redirect", pathname);
- return NextResponse.redirect(loginUrl);
- }
-
- // 简单验证 token 格式(不调用API,避免复杂依赖)
- if (token.length < 10) {
- console.log(`❌ Token 格式无效,重定向到登录页: ${pathname}`);
- const loginUrl = new URL("/login", request.url);
- loginUrl.searchParams.set("redirect", pathname);
- return NextResponse.redirect(loginUrl);
- }
-
- console.log(`✅ Token 存在,允许访问: ${pathname}`);
-
- // 创建响应并添加用户信息标记
- const response = NextResponse.next();
- response.headers.set('x-middleware-auth', 'validated');
-
- return response;
-
- } catch (error) {
- console.error(`❌ 中间件处理失败,重定向到登录页: ${pathname}`, error);
- // 发生错误时,重定向到登录页
- const loginUrl = new URL("/login", request.url);
- loginUrl.searchParams.set("redirect", pathname);
- return NextResponse.redirect(loginUrl);
- }
-}
-
-export const config = {
- matcher: [
- /*
- * 匹配所有路径除了:
- * - api (API routes)
- * - _next/static (static files)
- * - _next/image (image optimization files)
- * - favicon.ico (favicon file)
- * - login 和 register 页面
- */
- "/((?!api|_next/static|_next/image|favicon.ico|login|register).*)",
- ],
-};
\ No newline at end of file