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

NextAuth.js报错:不支持HTTP GET请求,signIn函数无法正常工作

解决NextAuth.js报错:"Error: This action with HTTP GET is not supported by NextAuth.js"

问题场景

使用Auth.js的signIn函数搭建静态登录页面时触发上述错误,尝试通过handleSubmit调用signIn授权用户会话却收到HTTP错误。

相关代码

Pages > API > Auth > [nextauth].js

import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"

export default NextAuth ({
    providers: [
        CredentialsProvider({
            name: "Credentials",
            credentials: {
                username: { label: "Username", type:"text", placeholder: 'user'},
                password: { label: "Password",  type:"text", placeholder:'password'},
            },

            async authorize(credentials) {
                if (credentials == null) return null; {
                    //login
                    const { username, password } = credentials;
                    if (!user) {
                        console.log('user is not found!')
                    }
                    const isMatch = await user.matchPassword(password);
                    if(!isMatch) {
                        throw new Error("Username or Password is incorrect")
                    }
                    return user;
                }
            }
        })
    ],
    callbacks: {
        async signIn({ user, account, profile, email, credentials }) {
            const isAllowedToSignIn = true
            if (isAllowedToSignIn) { 
            return true
            } else {
                return false
            }
        }
    },
    async redirect({url, baseUrl}) {
        // Allows relative callback URLs
        if(url.startsWith("/")) return `${baseUrl}${url}`
        // Allows callback URLs on the same origin
        else if ( new URL(url).origin === baseUrl) return url
        return baseUrl
    },
    async session({session, user, token}) {
        return session
    },
    async jwt({token, user, account, profile, isNewUser}) {
        return token
    },
        pages: {
            signIn: '/login.jsx',
        },

    secret: process.env.NEXTAUTH_SECRET,
    callbacks: {
        async jwt({token, user }) {
            if (user) {
                token.id = user._id.toString(); // Convert ObjectID to string
            }
        }
    }

})

Login.jsx文件

import React, { useState } from "react"
import Link from 'next/link';
import styled from 'styled-components';
import { Spacer } from "@nextui-org/react";
import { useRouter } from "next/router";
import {signIn} from "next-auth/react"

const Login = () => {
    const  [user, setUser] = useState('');
    const [pass, setPass] = useState('');
    const router = useRouter();

    const handleSubmit = (e) =>{
        e.preventDefault(e);
       console.log(user);
       console.log(pass);
       signIn();
       
       if (!user) {
        window.alert('Please provide username')
       }
       else if (!pass) {
        window.alert('Please provide password')
       } else {
        window.alert('Welcome' + ' ' + {user})
        router.push('../user-pages/profile')
       } 

    }

   
        return (
            <div className="authform">
            <div className="form">
                
           <form>
                <Spacer y={1} />
            <input name="userName"/>
            <label style={{color: "white", translate: -5}} form="userName">
                Username
                <input value={user} onChange={(e) => setUser(e.target.value)} type='username' placeholder='Username' id="Username" name='Username'/>
            </label>
           
            <Spacer y= {.25} />
                <br />
            <label style={{color: "White", translate: -5}} form="Password">Password</label>
            <input value={pass} onChange={(e) => setPass(e.target.value)}type="Password" placeholder="******" id='Password' name='Password' />

            <button type='submit' 
            onClick={signIn}>Log In</button>
           </form>
           <Spacer y={.75} />
           <a style={{color: "white"}} href='#'>Forgot Password?</a>
                <Spacer y={.25} />
           <Link style={{color: "white"}} href='../user-pages/signup'> Dont have an account? Register here! </Link>
           </div>
           </div>
        );
    };
 
export default Login;

错误原因及修复方案

1. Login.jsx核心问题(直接触发GET请求错误)

  • 按钮同时绑定type='submit'和onClick={signIn},点击时会发起两次请求,其中onClick直接调用signIn()会触发不被允许的GET请求。
  • 表单未绑定onSubmit到handleSubmit,自定义校验逻辑无法正确触发。
  • signIn调用未传递provider和表单数据,NextAuth无法识别认证请求。
  • 存在冗余表单字段干扰数据收集。

修正后的Login.jsx:

import React, { useState } from "react"
import Link from 'next/link';
import styled from 'styled-components';
import { Spacer } from "@nextui-org/react";
import { useRouter } from "next/router";
import { signIn } from "next-auth/react"

const Login = () => {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const router = useRouter();

    const handleSubmit = async (e) => {
        e.preventDefault();
        
        // 前端基础校验
        if (!username) {
            window.alert('请输入用户名');
            return;
        }
        if (!password) {
            window.alert('请输入密码');
            return;
        }

        // 指定credentials provider并传递表单数据
        const result = await signIn('credentials', {
            username,
            password,
            redirect: false // 手动处理跳转
        });

        if (result.ok) {
            window.alert(`欢迎回来,${username}`);
            router.push('/user-pages/profile');
        } else {
            window.alert(result.error || '登录失败,请检查用户名或密码');
        }
    };

    return (
        <div className="authform">
            <div className="form">
                <form onSubmit={handleSubmit}>
                    <Spacer y={1} />
                    <label style={{ color: "white", translate: -5 }} htmlFor="Username">
                        Username
                        <input 
                            value={username} 
                            onChange={(e) => setUsername(e.target.value)} 
                            type='text' 
                            placeholder='Username' 
                            id="Username" 
                            name='username' // 字段名与NextAuth配置一致
                        />
                    </label>
                    <Spacer y={.25} />
                    <br />
                    <label style={{ color: "White", translate: -5 }} htmlFor="Password">Password</label>
                    <input 
                        value={password} 
                        onChange={(e) => setPassword(e.target.value)}
                        type="password" 
                        placeholder="******" 
                        id='Password' 
                        name='password' // 字段名与NextAuth配置一致
                    />
                    <button type='submit'>Log In</button>
                </form>
                <Spacer y={.75} />
                <a style={{ color: "white" }} href='#'>Forgot Password?</a>
                <Spacer y={.25} />
                <Link style={{ color: "white" }} href='/user-pages/signup'>Dont have an account? Register here!</Link>
            </div>
        </div>
    );
};
 
export default Login;

2. [nextauth].js核心问题

  • 重复定义callbacks,后面的配置会覆盖前面的signIn回调。
  • authorize函数中user变量未定义,缺少实际用户查询逻辑。
  • pages.signIn路径错误,不需要加.jsx后缀。
  • redirect、session等顶级属性位置错误,被错误嵌套。

修正后的[nextauth].js:

import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
// 引入你的用户模型或查询方法,替换下面的占位逻辑
// import User from '../../../models/User';

export default NextAuth({
    providers: [
        CredentialsProvider({
            name: "Credentials",
            credentials: {
                username: { label: "Username", type: "text", placeholder: 'user' },
                password: { label: "Password", type: "password", placeholder: 'password' },
            },

            async authorize(credentials) {
                if (!credentials) return null;

                const { username, password } = credentials;
                
                // 替换为实际的用户查询逻辑,比如从数据库查找
                // const user = await User.findOne({ username });
                const user = null; // 临时占位,需替换

                if (!user) {
                    throw new Error("用户名不存在");
                }

                // 替换为实际的密码校验逻辑,比如bcrypt.compare
                // const isMatch = await bcrypt.compare(password, user.password);
                const isMatch = false; // 临时占位,需替换

                if (!isMatch) {
                    throw new Error("用户名或密码错误");
                }

                return user;
            }
        })
    ],
    callbacks: {
        async signIn({ user, account, profile, email, credentials }) {
            return true; // 可根据需求添加额外登录校验
        },
        async jwt({ token, user }) {
            if (user) {
                token.id = user._id?.toString();
            }
            return token; // 必须返回token,否则数据丢失
        },
        async session({ session, token }) {
            if (token.id) {
                session.user.id = token.id;
            }
            return session;
        }
    },
    redirect({ url, baseUrl }) {
        if (url.startsWith("/")) return `${baseUrl}${url}`;
        if (new URL(url).origin === baseUrl) return url;
        return baseUrl;
    },
    pages: {
        signIn: '/login', // 修正页面路径
    },
    secret: process.env.NEXTAUTH_SECRET,
})

关键注意事项

  • Credentials认证仅支持POST请求,禁止通过GET调用signIn。
  • signIn调用必须指定'credentials'作为provider,且表单字段名要与NextAuth配置中的credentials完全匹配。
  • authorize函数需返回用户对象(或null),校验失败时抛出的错误会被signIn返回结果捕获。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:38:12