Next.js自定义后端认证时,如何获取API返回的错误信息?
解决方案:在Next-Auth中返回自定义登录错误并实现重定向
核心问题分析
Next-Auth默认会将authorize函数中抛出的错误包装为通用的CredentialsSignin类型,导致客户端无法直接获取API返回的自定义错误信息(如"邮箱未验证")。要解决这个问题,关键在于让客户端能识别具体错误类型,并基于此执行重定向或提示逻辑。
步骤1:优化authorize函数,抛出明确错误信息
直接将API返回的错误信息抛出,无需额外包装,确保错误内容能传递到客户端:
authorize: async (credentials) => { const payload = await LoginSchema.parseAsync(credentials); const response = await loginUser(payload); const { status, user, message } = response as LoginResultProps; if (status !== "success") { // 直接抛出API返回的原始错误信息 throw new Error(message ?? "登录失败,请稍后重试"); } return user || null; },
步骤2:客户端调用signIn时禁用自动跳转,处理自定义错误
设置redirect: false阻止Next-Auth自动跳转,手动处理返回结果,根据错误信息执行重定向或提示:
try { // 关键:设置redirect: false,获取完整返回结果 const res = await signIn("credentials", { ...payload, redirect: false, }); if (!res?.error) { form.reset(); toast({ variant: "success", description: <ToastSuccess title="登录成功" /> }); const user_type = session?.data?.user.user_type as string; setTimeout(() => { if (user_type === "xx") router.push("/xx"); if (user_type === "yy") router.push("/yy"); if (user_type === "zz") router.push("/zz"); }, 1500); } else { // 根据错误信息区分处理逻辑 if (res.error.message === "Email not verified") { // 重定向到邮箱验证页面 router.push("/verify-email"); } else if (res.error.message === "Invalid login combination") { setNotificationType({ type: "failed", title: "登录失败", description: "用户名或密码错误" }); setIsOpenNotification(true); } else { setNotificationType({ type: "failed", title: "登录失败", description: res.error.message }); setIsOpenNotification(true); } } } catch (error) { if (error instanceof AuthError) { setNotificationType({ type: "failed", title: "登录失败", description: error.type === "CredentialsSignin" ? "无效登录凭证" : "登录出错" }); setIsOpenNotification(true); } else { console.error(error); setNotificationType({ type: "failed", title: "登录失败", description: "发生未知错误" }); setIsOpenNotification(true); } }
进阶:自定义错误类型(可选)
如果需要更严谨的错误区分,可以自定义错误类(注意:服务器端错误序列化后自定义属性可能丢失,建议优先用错误信息字符串判断):
// 自定义错误类 class AuthCustomError extends Error { type: "EmailNotVerified" | "InvalidCredentials" | "UnknownError"; constructor(message: string, type: "EmailNotVerified" | "InvalidCredentials" | "UnknownError") { super(message); this.type = type; } } // 在authorize中抛出 if (message?.toLowerCase() === "email not verified") { throw new AuthCustomError("Email not verified", "EmailNotVerified"); } else if (message?.toLowerCase() === "invalid login combination") { throw new AuthCustomError("Invalid login combination", "InvalidCredentials"); } else { throw new AuthCustomError(message ?? "登录失败", "UnknownError"); }
客户端处理时,通过错误信息字符串匹配即可(序列化后自定义type属性可能无法传递)。
内容的提问来源于stack exchange,提问作者Okiemute Gold
相关产品推荐
相关产品推荐

