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

Next-Auth v5.0.0-beta.5凭证认证失败时返回自定义错误的方法

NextAuth v5 凭证认证失败返回自定义错误方案

在NextAuth v5中,authorize函数的错误处理机制相比v4有调整,直接抛出JSON字符串形式的Error仍然可行,但需要配合客户端的signIn调用方式来正确获取并解析自定义错误信息。以下是具体实现方案:

服务器端配置(Auth Route)

修改你的认证路由文件(通常是app/api/auth/[...nextauth]/route.ts),在credentials provider的authorize函数中,当认证失败时抛出包含自定义错误信息的JSON字符串:

import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
// 导入你的API实例和类型定义
import AuthApiInstance from "@/services/auth-api";
import type { UserSchemaType } from "@/types/auth";
import { encryptCookieDataAction, EncryptionCookiesKeys } from "@/utils/cookies";

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    Credentials({
      credentials: {
        email: { label: "邮箱", type: "email" },
        password: { label: "密码", type: "password" },
      },
      async authorize(credentials) {
        // 校验必填参数
        if (!credentials?.email || !credentials?.password) {
          throw new Error(JSON.stringify({ 
            errors: "缺少邮箱或密码", 
            status: 400 
          }));
        }

        // 调用后端登录接口
        const urlencoded = new URLSearchParams();
        urlencoded.append('email', credentials.email);
        urlencoded.append('password', credentials.password);
        const res = await AuthApiInstance.signIn<UserSchemaType>(urlencoded);

        // 处理接口错误
        if (res.isError && !res.resData) {
          throw new Error(JSON.stringify({ 
            errors: res.error, 
            status: res.statusCode 
          }));
        }

        // 存储加密后的token
        if (res.resData?.data.token) {
          encryptCookieDataAction(res.resData.data.token, EncryptionCookiesKeys.AdminToken);
        }

        // 返回用户信息(认证成功)
        return res.resData?.data as any;
      },
    }),
  ],
  // 可选:指定错误页面(当redirect为true时跳转)
  pages: {
    error: "/auth/error",
  },
});

客户端处理方式

方式1:不跳转,直接获取错误(推荐)

调用signIn时设置redirect: false,这样会返回包含错误信息的结果对象,你可以直接解析并展示自定义错误:

"use client";

import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useState } from "react";

export default function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [loginError, setLoginError] = useState<{errors?: string, status?: number} | null>(null);
  const router = useRouter();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoginError(null);

    const result = await signIn("credentials", {
      email,
      password,
      redirect: false, // 禁止自动跳转
    });

    if (result?.error) {
      // 解析自定义错误信息
      try {
        const customError = JSON.parse(result.error);
        setLoginError(customError);
      } catch {
        // 解析失败时设置默认错误
        setLoginError({ errors: "登录失败", status: 500 });
      }
    } else if (result?.ok) {
      // 登录成功,跳转到目标页面
      router.push("/dashboard");
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="邮箱"
        required
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="密码"
        required
      />
      <button type="submit">登录</button>
      {loginError && (
        <div className="error">
          <p>错误信息:{loginError.errors}</p>
          <p>状态码:{loginError.status}</p>
        </div>
      )}
    </form>
  );
}

方式2:跳转到错误页面展示

如果使用默认的redirect: true(或不设置),认证失败后会跳转到你配置的错误页面,你可以通过useSearchParams获取错误参数并解析:

"use client";

import { useSearchParams } from "next/navigation";

export default function AuthErrorPage() {
  const searchParams = useSearchParams();
  const errorParam = searchParams.get("error");
  let errorInfo = null;

  if (errorParam) {
    try {
      errorInfo = JSON.parse(errorParam);
    } catch {
      errorInfo = { errors: "未知错误", status: 500 };
    }
  }

  return (
    <div className="auth-error">
      <h2>登录失败</h2>
      {errorInfo && (
        <>
          <p>错误详情:{errorInfo.errors}</p>
          <p>状态码:{errorInfo.status}</p>
        </>
      )}
      <a href="/login">返回登录页</a>
    </div>
  );
}

关键说明

  • v5中authorize函数仍可通过抛出Error传递错误信息,但需确保错误内容是可解析的JSON字符串。
  • 客户端必须通过redirect: false获取返回结果,或在错误页面解析URL查询参数,才能拿到自定义错误结构。
  • 若解析JSON失败,建议添加兜底逻辑,避免页面崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 14:38:18