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

如何在NextJS 13中用API路由、中间件实现用户认证及Cookie操作

Next.js 13 实现类似Express的用户认证逻辑与Cookie使用

核心对应关系

你在Express中通过protect中间件验证JWT、从Cookie取token、挂载req.user的逻辑,在Next.js 13中可以通过全局Middleware + API路由处理函数结合实现,同时Next.js对Cookie的读取/写入有专门的API支持。


1. 准备工具函数与依赖

先安装所需依赖:

npm install jsonwebtoken @types/jsonwebtoken cookie
# 或使用yarn
yarn add jsonwebtoken @types/jsonwebtoken cookie

创建通用JWT处理工具utils/auth.ts:

import jwt from "jsonwebtoken";
import { User } from "@/models/userModel"; // 你的User模型

// 验证JWT并返回用户信息
export const verifyToken = async (token: string): Promise<User | null> => {
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: string };
    // 从数据库获取用户,排除密码字段
    const user = await User.findById(decoded.userId).select("-password");
    return user;
  } catch (err) {
    return null;
  }
};

2. 实现全局认证中间件(Middleware)

Next.js 13的Middleware可在请求到达API路由/页面之前拦截处理,类似Express的全局中间件。在项目根目录创建middleware.ts:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { verifyToken } from "@/utils/auth";

export async function middleware(request: NextRequest) {
  // 从Cookie中获取JWT token
  const token = request.cookies.get("jwt")?.value;

  // 定义需要认证的路由
  const protectedPaths = ["/api/posts", "/api/profile"];
  const isProtected = protectedPaths.some(path => request.nextUrl.pathname.startsWith(path));

  if (isProtected) {
    if (!token) {
      // 无token,返回401
      return new NextResponse(JSON.stringify({ error: "Not authorized, no token" }), {
        status: 401,
        headers: { "Content-Type": "application/json" },
      });
    }

    const user = await verifyToken(token);
    if (!user) {
      // token无效,返回401
      return new NextResponse(JSON.stringify({ error: "Not authorized, invalid token" }), {
        status: 401,
        headers: { "Content-Type": "application/json" },
      });
    }

    // 将用户ID通过请求头传递给后续路由
    const requestHeaders = new Headers(request.headers);
    requestHeaders.set("x-user-id", user._id.toString());

    return NextResponse.next({
      request: { headers: requestHeaders },
    });
  }

  // 非保护路由直接放行
  return NextResponse.next();
}

// 指定Middleware生效的路由范围
export const config = {
  matcher: ["/api/:path*"],
};

注意: 若想直接在NextRequest上挂载user属性,可扩展类型:在types/next.d.ts中添加:

import type { User } from "@/models/userModel";

declare module "next/server" {
  interface NextRequest {
    user?: User;
  }
}

3. 在API路由中获取当前用户

类似Express中req.user的用法,在Next.js 13的API路由(App Router)中可这样获取用户:

示例:app/api/posts/route.ts

import { NextRequest, NextResponse } from "next/server";
import asyncHandler from "express-async-handler";
import { User } from "@/models/userModel";

// 处理POST请求创建帖子
export const POST = asyncHandler(async (req: NextRequest) => {
  const { content, image } = await req.json();
  
  // 从请求头获取用户ID并查询用户
  const userId = req.headers.get("x-user-id");
  if (!userId) {
    return NextResponse.json({ error: "Not authorized" }, { status: 401 });
  }
  const user = await User.findById(userId).select("-password");

  if (!user) {
    return NextResponse.json({ error: "User not found" }, { status: 404 });
  }

  // 后续逻辑:创建帖子并关联用户
  // const post = await Post.create({ content, image, author: user._id });

  return NextResponse.json({ message: "Post created", userName: user.name }, { status: 201 });
});

4. Cookie的读写操作

读取Cookie

在Middleware或API路由中,通过request.cookies.get("cookie-name")?.value读取:

const token = request.cookies.get("jwt")?.value;

设置Cookie

在登录接口中设置Cookie,示例:app/api/auth/login/route.ts

import { NextResponse } from "next/server";
import jwt from "jsonwebtoken";
import User from "@/models/userModel";

export const POST = async (req: NextRequest) => {
  const { email, password } = await req.json();
  
  // 验证用户密码逻辑(省略)
  const user = await User.findOne({ email });
  // ...密码验证步骤

  // 生成JWT
  const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET!, { expiresIn: "7d" });

  // 设置Cookie
  const response = NextResponse.json({ 
    message: "Login successful", 
    user: { name: user.name, email: user.email } 
  });
  response.cookies.set("jwt", token, {
    httpOnly: true, // 防止XSS攻击
    secure: process.env.NODE_ENV === "production", // 生产环境启用HTTPS
    maxAge: 7 * 24 * 60 * 60, // 7天有效期
    path: "/", // 全站生效
  });

  return response;
};

删除Cookie

登出时清除Cookie:

export const POST = async () => {
  const response = NextResponse.json({ message: "Logged out" });
  response.cookies.set("jwt", "", {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    maxAge: 0, // 立即过期
    path: "/",
  });
  return response;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 18:32:01