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

React NextAuth中Credentials为null且认证功能失效求助

问题描述
  1. 出现报错:Cannot convert undefined or null to object
  2. 添加{ providers !== null && ... }屏蔽错误后,页面可加载但认证完全失效,触发无反应
  3. 表单提交事件能触发,但signIn("credentials"...)未执行

第三方登录按钮渲染代码

return (
    <>
      {Object.values(providers).map((provider) => {
        if (provider.id === "credentials") {
          return null;
        }

        return (
          <div key={provider.name}>
            <Button
              variant="outlined"
              onClick={() => {
                setAppLoading(true);
                signIn(provider.id);
                setAppLoading(false);
              }}
              className="w-full uppercase !transform-none mt-4"
            >
              <Image
                height={24}
                width={24}
                src={`/logos/${provider.name}.svg` || "/logos/google.svg"}
                alt={provider.name}
              />
              <span className="ml-2 !text-[rgba(26, 26, 44, 0.5)]">
                Sign in with {provider.name}
              </span>
            </Button>
          </div>
        );
      })}
    </>
  );
};

表单提交事件代码

import { ClientSafeProvider, signIn } from "next-auth/client";

...

 onSubmit={async (values, { setErrors }) => {
          const { email, password } = values;

          setAppLoading(true);
          signIn("credentials", {
            email,
            password,
            redirect: false,
          }).then((res) => {
            setErrors({ error: res?.error });
          });

          setAppLoading(false);
        }}
...

[...nextauth].ts 配置代码

import login from "features/auth/login";
import register from "features/auth/register";
import NextAuth from "next-auth";
import Providers from "next-auth/providers";

export default NextAuth({
  providers: [
    Providers.Credentials({
      name: "Credentials",
      credentials: {
        name: { label: "Name", type: "text" },
        email: { label: "Email", type: "text" },
        password: { label: "Password", type: "password" },
      },

      async authorize(credentials, _req) {
        const { name, email, password } = credentials;
        alert("clicked");
        console.log("CLICKEEEED!!!!!!!!!!!!!!");
        if (typeof name === "undefined") {
          return login(email, password);
        }
        return register(name, email, password);
      },
    }),
    Providers.Google({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],
  pages: {
    signIn: "/auth/signin",
    signOut: "/auth/signout",
    error: "/auth/error", // Error code passed in query string as ?error=
    verifyRequest: "/auth/verify-request", // (used for check email message)
  },
  session: {
    jwt: true,
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },
});

解决方案

1. 修复Cannot convert undefined or null to object报错

直接判断providers是否存在,同时处理加载状态,避免初始值为null/undefined时调用Object.values:

return (
    <>
      {providers ? Object.values(providers).map((provider) => {
        if (provider.id === "credentials") {
          return null;
        }

        return (
          <div key={provider.name}>
            <Button
              variant="outlined"
              onClick={() => {
                setAppLoading(true);
                // 等待登录请求完成再关闭加载状态
                signIn(provider.id).finally(() => setAppLoading(false));
              }}
              className="w-full uppercase !transform-none mt-4"
            >
              <Image
                height={24}
                width={24}
                src={`/logos/${provider.name}.svg` || "/logos/google.svg"}
                alt={provider.name}
              />
              <span className="ml-2 !text-[rgba(26, 26, 44, 0.5)]">
                用{provider.name}登录
              </span>
            </Button>
          </div>
        );
      }) : <div>加载中...</div>}
    </>
  );
};

2. 修复signIn("credentials")不执行问题

表单提交里的setAppLoading(false)会在异步请求完成前执行,改用await处理异步逻辑:

onSubmit={async (values, { setErrors }) => {
  const { email, password } = values;

  setAppLoading(true);
  try {
    const res = await signIn("credentials", {
      email,
      password,
      redirect: false,
    });
    if (res?.error) {
      setErrors({ error: res.error });
    }
  } catch (err) {
    setErrors({ error: "登录失败,请重试" });
  } finally {
    setAppLoading(false);
  }
}}

3. 检查Credentials授权逻辑

  • authorize函数运行在服务端,里面的alert和console.log不会在浏览器控制台输出,调试请用服务端日志
  • 确保login和register函数验证成功时返回包含id、name、email的用户对象,验证失败返回null,示例:
async function login(email: string, password: string) {
  const res = await fetch("/api/auth/login", {
    method: "POST",
    body: JSON.stringify({ email, password }),
    headers: { "Content-Type": "application/json" },
  });
  const user = await res.json();
  return res.ok ? user : null;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:10:45