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

Next.js基于角色的组件访问控制:isAdmin校验始终不返回true

问题分析与解决方案

核心问题拆解

  1. 异步函数判断失效:checkAdminUser是异步函数,调用后返回Promise对象。直接在if条件中使用!checkAdminUser(...)时,Promise作为对象属于真值,导致!Promise始终为false;同时组件同步渲染时,异步请求还未完成,无法及时获取权限结果,权限逻辑完全失效。
  2. 空值未处理:session.user?.email可能为undefined,会导致API请求URL变为/api/user/undefined,返回错误结果。
  3. 前端校验不安全:前端权限判断可通过修改代码绕过,必须在服务器端做最终校验。

方案一:前端异步权限校验(临时辅助方案)

通过React状态管理处理异步校验逻辑,同时处理加载状态和空值:

const Dashboard: React.FC<Props> = (props) => {
  const { data: session, status } = useSession();
  const [isAdmin, setIsAdmin] = useState<boolean | null>(null); // null表示校验中

  useEffect(() => {
    const verifyAdmin = async () => {
      if (!session?.user?.email) {
        setIsAdmin(false);
        return;
      }
      try {
        // 编码邮箱避免特殊字符破坏URL
        const encodedEmail = encodeURIComponent(session.user.email);
        const result = await fetch(`/api/user/${encodedEmail}`, { method: "GET" });
        if (!result.ok) {
          setIsAdmin(false);
          return;
        }
        const user = await result.json();
        setIsAdmin(user.isAdmin === 1);
      } catch (error) {
        console.error(error);
        setIsAdmin(false);
      }
    };

    if (status === "authenticated") verifyAdmin();
    else if (status === "unauthenticated") setIsAdmin(false);
  }, [session, status]);

  // 加载状态处理
  if (status === "loading" || isAdmin === null) {
    return <Layout><div>加载中...</div></Layout>;
  }

  // 权限判断
  if (!session || !isAdmin) {
    return (
      <Layout>
        <AccessDenied />
      </Layout>
    );
  }

  return (
    <Layout>
      {/* 后台布局代码 */}
    </Layout>
  );
};

方案二:服务器端权限校验(推荐,安全高效)

直接在getServerSideProps中完成权限校验,避免前端绕开,同时减少API调用开销:

export const getServerSideProps: GetServerSideProps = async (context) => {
  // 获取会话信息
  const session = await getSession(context);
  
  // 无会话直接跳转权限拒绝页面
  if (!session?.user?.email) {
    return {
      redirect: {
        destination: "/access-denied",
        permanent: false,
      },
    };
  }

  // 服务器端直接查询用户权限(无需调用API)
  const user = await prisma.user.findUnique({
    where: { email: session.user.email },
    select: { isAdmin: true },
  });

  // 非管理员跳转
  if (!user || user.isAdmin !== 1) {
    return {
      redirect: {
        destination: "/access-denied",
        permanent: false,
      },
    };
  }

  // 获取仪表盘数据
  const dashboards = await prisma.dashboard.findMany({
    orderBy: { id: "asc" },
  });

  return {
    props: { dashboards: JSON.parse(JSON.stringify(dashboards)) },
  };
};

const Dashboard: React.FC<Props> = (props) => {
  // 能进入此处的均为已通过校验的管理员
  return (
    <Layout>
      {/* 后台布局代码 */}
    </Layout>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:25:40