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

Next.js中受保护API路由及服务器动作的认证问题解决

Next.js 服务器端跨API/服务器动作认证问题解决方案

核心问题根源

服务器端内部调用(API路由→API路由、服务器动作→API路由)时,不会自动携带客户端请求的认证Cookie,而NextAuth的保护机制依赖这些Cookie验证会话,导致认证失败。本地手动传Cookie可行但Vercel生产环境失效,通常是因为Cookie属性(Secure、SameSite)或请求配置(withCredentials)未正确设置。

最优解决方案:抽离共享认证逻辑

避免跨API的HTTP请求,直接把/api/get-token的认证逻辑抽成共享函数,在API路由和服务器动作中直接调用,彻底规避Cookie传递问题。

步骤1:抽离共享函数

创建utils/auth.ts,封装生成token的核心逻辑:

// utils/auth.ts
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/app/api/auth/[...nextauth]/route";

export async function generateToken() {
  // 直接通过NextAuth获取会话,和API路由的认证逻辑一致
  const session = await getServerSession(authOptions);
  
  if (!session) {
    throw new Error("Unauthorized: No valid session found");
  }

  // 原/api/get-token的token生成逻辑
  const token = "your-generated-token-string";
  return { token };
}

步骤2:在API路由中调用共享函数

修改/api/get-order-detail/[id]/route.ts:

// /api/get-order-detail/[id]/route.ts
import { NextRequest } from "next/server";
import { generateToken } from "@/utils/auth";

export async function GET(req: NextRequest) {
  try {
    const { token } = await generateToken();
    // 后续业务逻辑,使用token处理订单详情
    return Response.json({ token, message: "Token fetched successfully" });
  } catch (error) {
    return Response.json({ error: (error as Error).message }, { status: 401 });
  }
}

步骤3:在服务器动作中调用共享函数

修改/actions/get-order-detail.ts:

// /actions/get-order-detail.ts
"use server";
import { generateToken } from "@/utils/auth";

export const getOrderDetail = async () => {
  try {
    const { token } = await generateToken();
    // 后续业务逻辑,使用token获取订单详情
    return { success: true, token };
  } catch (error) {
    return { success: false, error: (error as Error).message };
  }
};

备选方案:强制传递Cookie(仅当必须跨API调用时使用)

如果因业务限制必须通过HTTP请求调用API,需确保正确传递Cookie头,并配置请求参数适配生产环境。

API路由间传递Cookie

修改/api/get-order-detail/[id]/route.ts,携带当前请求的Cookie头:

// /api/get-order-detail/[id]/route.ts
import axios from "axios";
import { NextRequest } from "next/server";
import { DOMAIN } from "@/config";

export async function GET(req: NextRequest) {
  // 获取当前请求的Cookie头
  const cookieHeader = req.headers.get("cookie") || "";

  try {
    const res = await axios.get(`${DOMAIN}/api/get-token`, {
      headers: { Cookie: cookieHeader },
      // 启用凭证传递,适配生产环境的Secure Cookie
      withCredentials: true,
    });
    return Response.json(res.data);
  } catch (error) {
    return Response.json({ error: "Authentication failed" }, { status: 401 });
  }
}

服务器动作中传递Cookie

服务器动作可通过next/headers的cookies()获取Cookie,拼接成请求头:

// /actions/get-order-detail.ts
"use server";
import axios from "axios";
import { cookies } from "next/headers";
import { DOMAIN } from "@/config";

export const getOrderDetail = async () => {
  // 从Cookie Store中获取所有Cookie并拼接成标准头格式
  const cookieStore = cookies();
  const cookieHeader = cookieStore.getAll().map(c => `${c.name}=${c.value}`).join("; ");

  try {
    const res = await axios.get(`${DOMAIN}/api/get-token`, {
      headers: { Cookie: cookieHeader },
      withCredentials: true,
    });
    return { success: true, data: res.data };
  } catch (error) {
    return { success: false, error: "Authentication failed" };
  }
};

生产环境(Vercel)注意事项

  1. Cookie属性配置:确保NextAuth的Cookie设置secure: process.env.NODE_ENV === "production",sameSite: "lax"(同域场景),避免Cookie被浏览器拦截。
  2. 域名一致性:DOMAIN需设置为生产环境的完整域名(如https://your-vercel-app.vercel.app),避免跨域Cookie传递问题。
  3. Vercel Edge Runtime:若使用Edge Runtime,需确保getServerSession或cookies()适配Edge环境(NextAuth v4+已支持)。

内容的提问来源于stack exchange,提问作者Jagdish Padeliya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:00:22