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

Next.js 13 NextAuth中间件异常:已登录用户仍需重新登录

已登录用户访问受保护路由仍被要求重新登录(NextAuth中间件+Prisma适配器)

我用NextAuth中间件保护了/api/:path*和/new路由,要求未登录用户必须登录,但已登录用户访问/new时还是会被强制跳转到登录页,排查后发现问题出在/api/:path*的匹配规则上。使用Prisma作为NextAuth的适配器,相关代码如下:

中间件文件

export {default} from "next-auth/middleware";

export const config = {
    matcher: ["/api/:path*", "/new"]
}

NextAuth配置文件(/api/auth/[...nextauth]/options.ts)

// /api/auth/[...nextauth]/options.ts
import { prisma } from "@/lib/database";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { type NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github";
import GoogleProvider from "next-auth/providers/google";

export const authOptions: NextAuthOptions = {
  adapter: PrismaAdapter(prisma),
  secret: process.env.NEXTAUTH_SECRET,
  session: {
    maxAge: 30 * 60,
  },
  debug: process.env.NODE_ENV === "development" ? true : false,
  pages: {
    signIn: "/auth/login",
  },
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_CLIENT_ID as string,
      clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
    }),
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
    }),
  ],
};

路由文件(/api/auth/[...nextauth]/route.ts)

import NextAuth from "next-auth/next";
import { authOptions } from "./options";

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

Prisma Schema文件

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider     = "mysql"
  url          = env("DATABASE_URL")
  relationMode = "prisma"
}

model Todo {
  id               String   @id @default(cuid())
  todo_name        String
  todo_description String?
  completed        Boolean? @default(false)
  createdAt        DateTime @default(now())
  updatedAt        DateTime @updatedAt
  user             User?    @relation(fields: [userId], references: [id])
  userId           String?

  @@index([userId])
}

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
  @@index([userId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
  todos         Todo[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

解决方案

问题根源在于/api/:path*的匹配规则把NextAuth自身的认证API路由(比如/api/auth/session)也包含进去了,中间件拦截这些请求后,NextAuth无法正常读取用户会话,导致误判用户未登录。

你需要修改中间件的匹配规则,排除NextAuth的认证路由,有两种写法:

写法一:使用excludedRoutes

export {default} from "next-auth/middleware";

export const config = {
    matcher: ["/api/:path*", "/new"],
    excludedRoutes: ["/api/auth/:path*"]
}

写法二:使用否定匹配语法

export {default} from "next-auth/middleware";

export const config = {
    matcher: ["/((?!api/auth).*)", "/new"]
}

如果你的API路由只有部分需要保护,更推荐精准指定需要保护的路径(比如/api/todos/:path*),避免大范围匹配带来的意外问题。

原因说明

当中间件匹配/api/:path*时,NextAuth用来验证会话的/api/auth/session请求会被拦截。中间件本身需要依赖这个接口获取用户会话状态,但此时接口被自己拦截,形成循环,导致无法正确识别已登录用户,最终强制跳转到登录页。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:35:22