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

NextAuth使用数据库适配器时的凭证登录问题求助

NextAuth 凭证登录与GoogleProvider兼容问题解决

问题根源

启用MongoDBAdapter时,NextAuth默认会话策略为database,但CredentialsProvider并不适配数据库会话模式,导致凭证登录失败。切换到jwt策略后,若未配置对应的JWT与会话回调,GoogleProvider无法正确序列化用户信息到JWT中,进而导致第三方登录失效。

解决步骤

  1. 固定会话策略为JWT,显式声明session: { strategy: "jwt" }
  2. 配置JWT回调:在jwt回调中添加用户关键信息(如ID、邮箱),确保JWT令牌包含完整用户标识
  3. 配置会话回调:将JWT中的用户信息映射到会话对象,保证前端能正确获取用户数据
  4. 优化CredentialsProvider的authorize逻辑:确保返回的用户结构包含必要字段,同时避免重复建立MongoDB连接

修正后的完整代码

import { User } from "@/models/User";
import mongoose from "mongoose";
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import bcrypt from "bcrypt";
import { MongoDBAdapter } from "@auth/mongodb-adapter";
import clientPromise from "@/libs/mongoConnect";
import { getServerSession } from "next-auth";

async function getUser() {
  const session = await getServerSession(authOptions);
  return session?.user;
}

export const authOptions = {
  adapter: MongoDBAdapter(clientPromise),
  secret: process.env.SECRET,
  // 显式指定JWT会话策略
  session: {
    strategy: "jwt",
  },
  providers: [
    GoogleProvider({
      id: "google",
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
    CredentialsProvider({
      name: "Credentials",
      id: "credentials",
      credentials: {
        email: {
          label: "Email",
          type: "email",
          placeholder: "test@example.com",
        },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        // 避免重复连接数据库,建议在全局初始化连接
        if (!mongoose.connection.readyState) {
          await mongoose.connect(process.env.MONGO_URL);
        }
        
        const user = await User.findOne({ email: credentials?.email });
        if (!user) return null;

        const passwordOk = bcrypt.compareSync(credentials?.password || "", user.password);
        if (!passwordOk) return null;

        // 返回包含必要字段的用户对象,适配JWT序列化
        return {
          id: user._id.toString(),
          email: user.email,
          name: user.name,
          // 其他你需要的字段
        };
      },
    }),
  ],
  // JWT回调:添加用户信息到令牌
  callbacks: {
    async jwt({ token, user }) {
      // 首次登录时,将用户信息合并到token
      if (user) {
        token.id = user.id;
        token.email = user.email;
        token.name = user.name;
      }
      return token;
    },
    // 会话回调:将JWT信息映射到session.user
    async session({ session, token }) {
      if (token) {
        session.user.id = token.id;
        session.user.email = token.email;
        session.user.name = token.name;
      }
      return session;
    },
  },
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

关键说明

  • 配置jwt和session回调是核心:JWT策略下,用户信息需要手动从登录返回的user对象同步到JWT令牌,再从令牌同步到会话对象
  • CredentialsProvider的authorize函数必须返回包含id、email等标准字段的对象,否则JWT无法正确序列化
  • 优化MongoDB连接逻辑,避免每次登录都重复建立连接

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:54:56