Next.js 14生产部署时Middleware无法提取Cookie问题求助
环境版本
- next: "14.1.3"
- next-auth: "^4.22.1"
问题详情
开发环境下,通过手动检查请求头Cookie实现Next.js中间件认证功能正常,但部署到Vercel后无法提取Cookie。尝试使用next-auth的withAuth中间件同样无效。由于Edge Function不支持getServerSession,因此采用手动检查Cookie并调用/api/auth/session接口验证会话的方案。
中间件代码
import { cookies } from "next/headers"; import { NextResponse, NextRequest } from "next/server"; export async function middleware(request: NextRequest) { const _cookies = cookies(); const allCookies = _cookies .getAll() .map((cookeie) => `${cookeie.name}=${cookeie.value}`) .join(";"); if (!_cookies.get("next-auth.session-token")?.value?.trim()) { return NextResponse.redirect(new URL("/signin", request.url)); } const headers = { "Content-Type": "application/json", Cookie: allCookies, }; /** * Send a request to /api/auth/session to get the user session * process.LOOPBACK_URL can be set as localhost, or your website url */ const url = new URL("/api/auth/session", process.env.LOOPBACK_URL); const response = await fetch(url.href, { headers: headers, cache: "no-store", }); if (response.ok) { const session = await response.json(); if (new Date(session.expires) < new Date()) { return NextResponse.redirect(new URL("/signin", request.url)); } return NextResponse.next(); } return NextResponse.redirect(new URL("/signin", request.url)); } // See "Matching Paths" below to learn more export const config = { matcher: ["/account", "/analytics"], }; // Next Auth does not work with Edge Function so we can not use getServerSession of next Auth
NextAuth配置代码
import { MongoDBAdapter } from "@auth/mongodb-adapter"; import clientPromise from "@/app/libs/mongodb"; import GoogleAuthProvider from "next-auth/providers/google"; import { NextAuthOptions } from "next-auth"; export const authOption: NextAuthOptions = { // @ts-ignore adapter: MongoDBAdapter(clientPromise), providers: [ GoogleAuthProvider({ clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }), ], session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60, // 30 days updateAge: 24 * 60 * 60, // 24 hours }, pages: { signIn: "/signin" }, secret: process.env.NEXTAUTH_SECRET as string, callbacks: { async jwt({ token, user, account, profile }) { return token; }, }, };
解决方案
1. 修正Cookie的生产环境配置
Vercel部署后默认使用HTTPS,需确保NextAuth的Cookie适配生产环境规则:
在authOption中添加cookies配置,明确设置Secure和SameSite属性:
export const authOption: NextAuthOptions = { // ... 原有配置 cookies: { sessionToken: { name: `next-auth.session-token`, options: { httpOnly: true, sameSite: "lax", path: "/", secure: process.env.NODE_ENV === "production", }, }, }, };
2. 中间件中优先使用Request自带的Cookie
Edge环境下,直接从request.cookies获取Cookie比next/headers的cookies()函数更可靠:
export async function middleware(request: NextRequest) { // 直接从request对象提取Cookie const sessionToken = request.cookies.get("next-auth.session-token")?.value?.trim(); if (!sessionToken) { return NextResponse.redirect(new URL("/signin", request.url)); } // 调用会话接口时复用请求头,无需手动拼接Cookie const url = new URL("/api/auth/session", request.nextUrl.origin); const response = await fetch(url.href, { headers: { ...request.headers, "Content-Type": "application/json", }, cache: "no-store", }); if (response.ok) { const session = await response.json(); if (new Date(session.expires) < new Date()) { return NextResponse.redirect(new URL("/signin", request.url)); } return NextResponse.next(); } return NextResponse.redirect(new URL("/signin", request.url)); }
3. 正确使用withAuth中间件
若要使用官方withAuth,需适配Edge环境的配置方式:
import { withAuth } from "next-auth/middleware"; import { NextResponse } from "next/server"; export default withAuth( function middleware(request) { return NextResponse.next(); }, { callbacks: { authorized: ({ token }) => !!token, }, pages: { signIn: "/signin", }, } ); export const config = { matcher: ["/account", "/analytics"], };
注意:确保authOption在app/api/auth/[...nextauth]/route.ts中正确导入并使用。
4. 验证生产环境变量LOOPBACK_URL
部署到Vercel后,LOOPBACK_URL需设置为你的生产域名(如https://your-domain.vercel.app),不能使用localhost,否则会导致跨域请求失败。
内容的提问来源于stack exchange,提问作者user21934236
相关产品推荐
相关产品推荐

