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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:25:21