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

Next.js中间件调用数据库获取用户角色返回undefined问题

解决Next.js Middleware中获取用户角色返回undefined的问题

问题描述

在Next.js的middleware.ts中,我通过NextAuth完成身份验证后能成功获取用户邮箱,但调用自定义的getUserRoleByEmail方法时,返回的user结果为undefined,无法完成管理员权限校验。

相关代码

获取用户角色的函数

export const getUserRoleByEmail = async (email: string) => {
  try {
    const user = await db.user.findFirst({ where: { email }, select: { role: true } });
    return user;
  } catch {
    return null;
  }
};

Middleware代码

//middleware.ts

import NextAuth from "next-auth";

import authConfig from "@/auth.config";
import {
  DEFAULT_LOGIN_REDIRECT,
  adminRoutes,
  apiAuthPrefix,
  authRoutes,
  publicRoutes,
} from "@/routes";
import { getUserRoleByEmail } from "./data/user";

const { auth } = NextAuth(authConfig);
//@ts-ignore
export default auth(async (req) => {
  const { nextUrl } = req;
  const isLoggedIn = !!req.auth;

  const isApiAuthRoute = nextUrl.pathname.startsWith(apiAuthPrefix);
  const isPublicRoute = publicRoutes.includes(nextUrl.pathname);
  const isAuthRoute = authRoutes.includes(nextUrl.pathname);
  const isAdminRoute = adminRoutes.includes(nextUrl.pathname);

  if (isApiAuthRoute) {
    return null;
  }

  if (isAuthRoute) {
    if (isLoggedIn) {
      return Response.redirect(new URL(DEFAULT_LOGIN_REDIRECT, nextUrl))
    }
    return null;
  }

  if (!isLoggedIn && !isPublicRoute) {
    return Response.redirect(new URL("/auth/login", nextUrl));
  }

  const email = req.auth?.user?.email!;
  //trying to get the role
  const user = await getUserRoleByEmail(email)

  if (isAdminRoute && email !== process.env.ADMIN_EMAIL && user?.role !== "ADMIN") {
    return Response.redirect(new URL("/auth/login-as-admin", nextUrl));
  }

  return null;
})

// Optionally, don't invoke Middleware on some paths
export const config = {
  matcher: ['/((?!.+\.[\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
}

排查与解决步骤

1. 检查getUserRoleByEmail函数有效性

  • 验证数据库连接:确认db实例在Middleware的Edge Runtime环境下能正常访问数据库(比如Prisma需适配Edge环境,需导入@prisma/client/edge而非默认包)。
  • 添加错误日志:修改函数的catch块,打印具体错误信息,定位查询失败原因:
    export const getUserRoleByEmail = async (email: string) => {
      try {
        const user = await db.user.findFirst({ where: { email }, select: { role: true } });
        return user;
      } catch (error) {
        console.error('获取用户角色失败:', error);
        return null;
      }
    };
    
  • 直接验证数据库查询:手动执行SQL语句SELECT role FROM user WHERE email = '你的测试邮箱',确认数据库中存在该邮箱的用户且role字段有值。

2. 修正Middleware中的参数处理

  • 移除强制非空断言:原代码中const email = req.auth?.user?.email!;的!会强制断言邮箱非空,若实际req.auth?.user?.email为undefined,会传入无效参数导致查询失败,改为:
    const email = req.auth?.user?.email;
    if (!email) {
      return Response.redirect(new URL("/auth/login", nextUrl));
    }
    const user = await getUserRoleByEmail(email);
    
  • 确认req.auth数据正确性:在获取邮箱前打印req.auth,确认user.email确实存在且格式正确。

3. 优化权限校验逻辑

当user为null或undefined时,当前逻辑会直接判定用户非管理员,可调整逻辑更严谨:

if (isAdminRoute) {
  if (email === process.env.ADMIN_EMAIL) {
    return null;
  }
  if (!user || user.role !== "ADMIN") {
    return Response.redirect(new URL("/auth/login-as-admin", nextUrl));
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 19:53:29