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

NextAuth与Middleware配置问题:登录后仍可访问登录页

问题解决:已登录状态仍可访问登录页 + Middleware未触发

核心问题分析

  1. Middleware未触发登录页:NextAuth 的 /api/auth/* 路由默认由自身逻辑优先处理,自定义 Middleware 不会生效;同时 withAuth 默认跳过登录页的授权检查,不会执行内部回调。
  2. 权限逻辑隐患:原代码中对 /api/auth 的拦截会导致未登录用户重定向到登录页时触发循环跳转,且用 includes 判断路径容易误匹配。

修复步骤

1. 修改 Middleware 配置,强制触发登录页检查

添加路由匹配规则,调整 withAuth 配置让所有请求进入自定义逻辑:

import { withAuth, NextRequest, NextResponse } from "next-auth/middleware";

export default withAuth(
  async function middleware(request: NextRequest) {
    const { token } = request.nextauth;
    console.log('on middleware');

    // 已登录用户访问登录页,直接跳转对应仪表盘
    if (token && request.nextUrl.pathname === "/api/auth/signin") {
      const target = token.user.role === "PARTNER" 
        ? "/cms/partner/dashboard" 
        : "/cms/admin/dashboard";
      return NextResponse.redirect(new URL(target, request.url));
    }

    // 未登录用户访问权限页,跳转登录页
    if (!token && request.nextUrl.pathname !== "/api/auth/signin") {
      return NextResponse.redirect(new URL("/api/auth/signin", request.url));
    }

    // 角色权限校验
    if (token) {
      if (token.user.role === "PARTNER" && request.nextUrl.pathname.startsWith("/cms/admin")) {
        return NextResponse.redirect(new URL("/cms/partner/dashboard", request.url));
      }
      if (token.user.role === "ADMIN" && request.nextUrl.pathname.startsWith("/cms/partner")) {
        return NextResponse.redirect(new URL("/cms/admin/dashboard", request.url));
      }
    }
  },
  {
    secret: process.env.NEXTAUTH_SECRET,
    // 强制所有匹配路径进入自定义Middleware
    callbacks: {
      authorized: () => true,
    },
  }
);

// 指定需要Middleware处理的路由
export const config = {
  matcher: [
    "/api/auth/signin",
    "/cms/admin/:path*",
    "/cms/partner/:path*",
  ],
};

2. 优化 NextAuth 配置(类型安全+错误处理)

import NextAuth, { AuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

// 定义用户类型
interface AppUser {
  id: string;
  role: "ADMIN" | "PARTNER";
  token: string;
}

const handler = NextAuth({
  session: {
    strategy: "jwt",
  },
  providers: [
    CredentialsProvider({
      name: "Sign in",
      credentials: {
        username: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        if (!credentials?.username || !credentials?.password) return null;

        try {
          const { data } = await api.post("/cms/auth/login", {
            username: credentials.username,
            password: credentials.password,
          });
          return {
            id: Math.random().toString(),
            role: data.data.role,
            token: data.data.token,
          } as AppUser;
        } catch {
          // 登录失败返回null,NextAuth会提示错误
          return null;
        }
      },
    }),
  ],
  callbacks: {
    async session({ session, token }) {
      session.user = token.user as AppUser;
      return session;
    },
    async jwt({ token, user }) {
      if (user) token.user = user;
      return token;
    },
  },
  secret: process.env.NEXTAUTH_SECRET,
} satisfies AuthOptions);

export { handler as GET, handler as POST };

关键优化点

  • 路由匹配:用 matcher 明确指定需要处理的路由,确保登录页被覆盖。
  • 强制触发:authorized: () => true 让 withAuth 不再跳过任何路径,完全由自定义逻辑控制权限。
  • 路径判断:用 startsWith 替代 includes,避免误匹配无关路径。
  • 错误处理:添加登录失败的异常捕获,避免程序崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:18:24