使用NextAuth时出现Fetch错误的求助(Next.js 13.4.7)
NextAuth Credentials Provider登录提交后重定向错误排查(Next.js 13.4.7)
问题描述
基于Next.js 13.4.7构建的项目,使用NextAuth的Credentials Provider实现用户认证,核心代码位于/src/app/api/auth/[...nextauth]/route.ts。点击登录按钮可正常跳转至自定义登录表单,但提交表单后会被重定向到Next.js默认错误页面,控制台无明确报错信息,仅提示问题与路径及Fetch操作相关。
核心代码
import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import { loginUser } from "@/services/auth"; export const authOptions = { providers: [ CredentialsProvider({ name: "Credentials", credentials: { username: { label: "Username", type: "text", placeholder: "jsmith", }, password: { label: "Password", type: "password" }, }, async authorize(credentials, req) { const res = await fetch( "http://localhost:1337/api/auth/local", { method: "POST", body: JSON.stringify({ identifier: credentials?.username, password: credentials?.password, }), headers: { "Content-Type": "application/json", }, } ); const user = await res.json(); console.log(res, " res"); if (user) { return user; } return null; }, }), ], pages: { signIn: "/login", }, }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };
错误表现
提交表单后跳转至Next.js默认404错误页面,提示页面无法找到。
排查与解决方案
1. 规范authorize函数返回值
NextAuth要求authorize返回的用户对象必须包含唯一标识字段(默认是id),而Strapi返回的登录结果结构通常为{ jwt: string, user: { id: number, ... } },直接返回原始数据会导致NextAuth无法识别用户标识,引发后续重定向错误。需手动映射字段:
async authorize(credentials, req) { const res = await fetch("http://localhost:1337/api/auth/local", { method: "POST", body: JSON.stringify({ identifier: credentials?.username, password: credentials?.password, }), headers: { "Content-Type": "application/json" }, }); if (!res.ok) { // 登录失败时抛出错误,NextAuth会自动跳转回登录页并显示错误 throw new Error("用户名或密码错误"); } const { jwt, user } = await res.json(); // 返回符合NextAuth要求的用户对象 if (user && jwt) { return { id: user.id, name: user.username, email: user.email, jwt: jwt }; } return null; }
2. 处理Fetch请求错误状态
原代码未判断请求响应状态,即便Strapi返回401(未授权)、400(参数错误)等状态码,仍会解析JSON并返回user,导致NextAuth误判认证成功,进而触发异常重定向。添加响应状态检查可避免此类问题。
3. 配置JWT会话策略
Credentials Provider推荐使用JWT会话策略,需在authOptions中补充session和callbacks配置,确保用户信息能正确存储和传递:
export const authOptions = { providers: [/* ... 现有Provider配置 ... */], pages: { signIn: "/login" }, // 新增JWT会话配置 session: { strategy: "jwt", }, callbacks: { async jwt({ token, user }) { // 首次登录时将user信息合并到token if (user) { token.id = user.id; token.jwt = user.jwt; token.name = user.name; token.email = user.email; } return token; }, async session({ session, token }) { // 将token中的信息同步到session,供前端使用 session.user.id = token.id; session.user.jwt = token.jwt; return session; }, }, };
4. 确保登录表单提交逻辑正确
避免直接用HTML表单提交,建议使用NextAuth提供的signIn方法处理登录,确保跳转逻辑符合框架规范:
// 登录组件示例 "use client"; import { signIn } from "next-auth/react"; export default function LoginPage() { const handleSubmit = async (e) => { e.preventDefault(); const formData = new FormData(e.target); const username = formData.get("username"); const password = formData.get("password"); const result = await signIn("credentials", { username, password, redirect: true, callbackUrl: "/", // 登录成功后跳转的目标路径 }); }; return ( <form onSubmit={handleSubmit}> <input type="text" name="username" placeholder="用户名" /> <input type="password" name="password" placeholder="密码" /> <button type="submit">登录</button> </form> ); }
内容的提问来源于stack exchange,提问作者Vanesa
相关产品推荐
相关产品推荐

