You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14生产部署时Middleware无法提取Cookie问题求助

问题:Next.js 中间件在Vercel部署后无法提取NextAuth 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:52:47