From 0df19c9cfbed329fe90c4044edd5eb8c67d586cb Mon Sep 17 00:00:00 2001 From: peng Date: Fri, 31 Oct 2025 17:08:25 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=9F=E4=BA=A7=E7=AE=A1=E7=90=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=20-=20=E4=B8=AD=E9=97=B4=E4=BB=B6=E6=8B=A6=E6=88=AA?= =?UTF-8?q?=E6=89=80=E6=9C=89=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crop-x/next-env.d.ts | 2 +- crop-x/package-lock.json | 95 ++++++++++++---------- crop-x/package.json | 2 +- crop-x/src/components/auth/AuthContext.tsx | 37 +++++++++ crop-x/src/middleware.ts | 75 +++++++++++++++++ 5 files changed, 165 insertions(+), 46 deletions(-) create mode 100644 crop-x/src/middleware.ts diff --git a/crop-x/next-env.d.ts b/crop-x/next-env.d.ts index 830fb59..c4b7818 100644 --- a/crop-x/next-env.d.ts +++ b/crop-x/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -/// +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/crop-x/package-lock.json b/crop-x/package-lock.json index e7f01fa..f7d43f4 100644 --- a/crop-x/package-lock.json +++ b/crop-x/package-lock.json @@ -44,7 +44,7 @@ "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^0.487.0", - "next": "^15.5.6", + "next": "^16.0.1", "next-themes": "^0.4.6", "openapi-fetch": "^0.15.0", "qrcode": "*", @@ -1536,9 +1536,9 @@ } }, "node_modules/@next/env": { - "version": "15.5.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.6.tgz", - "integrity": "sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/env/-/env-16.0.1.tgz", + "integrity": "sha512-LFvlK0TG2L3fEOX77OC35KowL8D7DlFF45C0OvKMC4hy8c/md1RC4UMNDlUGJqfCoCS2VWrZ4dSE6OjaX5+8mw==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1582,12 +1582,13 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.6", - "resolved": "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.6.tgz", - "integrity": "sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.1.tgz", + "integrity": "sha512-R0YxRp6/4W7yG1nKbfu41bp3d96a0EalonQXiMe+1H9GTHfKxGNCGFNWUho18avRBPsO8T3RmdWuzmfurlQPbg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1597,12 +1598,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.5.6", - "resolved": "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.6.tgz", - "integrity": "sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.1.tgz", + "integrity": "sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1612,12 +1614,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.6", - "resolved": "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.6.tgz", - "integrity": "sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.1.tgz", + "integrity": "sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1627,12 +1630,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.6", - "resolved": "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.6.tgz", - "integrity": "sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.1.tgz", + "integrity": "sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1642,12 +1646,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.6", - "resolved": "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.6.tgz", - "integrity": "sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.1.tgz", + "integrity": "sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1657,12 +1662,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.6", - "resolved": "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.6.tgz", - "integrity": "sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.1.tgz", + "integrity": "sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1672,12 +1678,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.6", - "resolved": "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.6.tgz", - "integrity": "sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.1.tgz", + "integrity": "sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1687,9 +1694,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.6.tgz", - "integrity": "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.1.tgz", + "integrity": "sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==", "cpu": [ "x64" ], @@ -8939,12 +8946,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "15.5.6", - "resolved": "https://registry.npmjs.org/next/-/next-15.5.6.tgz", - "integrity": "sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==", + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/next/-/next-16.0.1.tgz", + "integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==", "license": "MIT", "dependencies": { - "@next/env": "15.5.6", + "@next/env": "16.0.1", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -8954,18 +8961,18 @@ "next": "dist/bin/next" }, "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.5.6", - "@next/swc-darwin-x64": "15.5.6", - "@next/swc-linux-arm64-gnu": "15.5.6", - "@next/swc-linux-arm64-musl": "15.5.6", - "@next/swc-linux-x64-gnu": "15.5.6", - "@next/swc-linux-x64-musl": "15.5.6", - "@next/swc-win32-arm64-msvc": "15.5.6", - "@next/swc-win32-x64-msvc": "15.5.6", - "sharp": "^0.34.3" + "@next/swc-darwin-arm64": "16.0.1", + "@next/swc-darwin-x64": "16.0.1", + "@next/swc-linux-arm64-gnu": "16.0.1", + "@next/swc-linux-arm64-musl": "16.0.1", + "@next/swc-linux-x64-gnu": "16.0.1", + "@next/swc-linux-x64-musl": "16.0.1", + "@next/swc-win32-arm64-msvc": "16.0.1", + "@next/swc-win32-x64-msvc": "16.0.1", + "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -12349,7 +12356,7 @@ }, "node_modules/react": { "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "resolved": "https://registry.npmmirror.com/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", "engines": { @@ -12379,7 +12386,7 @@ }, "node_modules/react-dom": { "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", "dependencies": { diff --git a/crop-x/package.json b/crop-x/package.json index f7821a2..2ffbcde 100644 --- a/crop-x/package.json +++ b/crop-x/package.json @@ -54,7 +54,7 @@ "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^0.487.0", - "next": "^15.5.6", + "next": "^16.0.1", "next-themes": "^0.4.6", "openapi-fetch": "^0.15.0", "qrcode": "*", diff --git a/crop-x/src/components/auth/AuthContext.tsx b/crop-x/src/components/auth/AuthContext.tsx index e5038ab..03dd8a5 100644 --- a/crop-x/src/components/auth/AuthContext.tsx +++ b/crop-x/src/components/auth/AuthContext.tsx @@ -3,6 +3,21 @@ import React, { createContext, useContext, useState, ReactNode } from 'react'; import { getCurrentUserInfoApiV1AuthMeGet } from '@/lib/api/sdk.gen'; +// Cookie 操作工具 +const setTokenCookie = (token: string) => { + if (typeof document !== 'undefined') { + document.cookie = `auth-token=${token}; path=/; max-age=${7 * 24 * 60 * 60}`; + console.log('🍪 Token已设置到cookie'); + } +}; + +const removeTokenCookie = () => { + if (typeof document !== 'undefined') { + document.cookie = 'auth-token=; path=/; max-age=0'; + console.log('🗑️ Token已从cookie中清除'); + } +}; + interface User { id: string; username: string; @@ -36,12 +51,19 @@ export function AuthProvider({ children }: AuthProviderProps) { setUser(userData); // 存储到 localStorage localStorage.setItem('user', JSON.stringify(userData)); + + // 同时设置 cookie(供中间件使用) + if (userData.token) { + setTokenCookie(userData.token); + } + setLoading(false); }; const logout = () => { setUser(null); localStorage.removeItem('user'); + removeTokenCookie(); // 清除 cookie setLoading(false); }; @@ -88,6 +110,21 @@ export function AuthProvider({ children }: AuthProviderProps) { // 初始化时检查 localStorage并验证用户 React.useEffect(() => { + // 检查是否有存储的用户信息和 token,并设置 cookie + const storedUser = localStorage.getItem('user'); + if (storedUser) { + try { + const userData = JSON.parse(storedUser); + if (userData.token && !document.cookie.includes('auth-token')) { + setTokenCookie(userData.token); + console.log('🔄 初始化时设置cookie'); + } + } catch (error) { + console.error('解析存储用户信息失败:', error); + localStorage.removeItem('user'); + } + } + validateUser(); }, []); diff --git a/crop-x/src/middleware.ts b/crop-x/src/middleware.ts new file mode 100644 index 0000000..50d8abb --- /dev/null +++ b/crop-x/src/middleware.ts @@ -0,0 +1,75 @@ +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