启用MongoDB Adapter后NextAuth的CredentialsProvider登录失败
NextAuth搭配MongoDB Adapter与CredentialsProvider登录失败问题解决
问题描述
使用NextAuth结合MongoDB Adapter和CredentialsProvider实现用户名密码认证时,启用MongoDB Adapter后登录功能失效,禁用Adapter则可正常登录,推测CredentialsProvider的authorize处理器存在数据库访问异常。
代码示例
auth.js
import mongoose from "mongoose"; import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import { User } from "@/app/models/User"; import bcrypt from "bcrypt"; import GoogleProvider from "next-auth/providers/google"; import { MongoDBAdapter } from "@auth/mongodb-adapter"; import clientPromise from "@/libs/mongoConnect"; export const authOptions = { secret: process.env.SECRET, adapter: MongoDBAdapter(clientPromise), providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), CredentialsProvider({ name: "credentials", id: "credentials", credentials: { username: { label: "Email", type: "email", placeholder: "test@example.com", }, password: { label: "Password", type: "password" }, }, async authorize(credentials, req) { const email = credentials?.email; const password = credentials?.password; mongoose.connect(process.env.MONGO_URL); const user = await User.findOne({ email }); const passwordOk = user && bcrypt.compareSync(password, user.password); if (passwordOk) { return user; } return null; }, }), ], }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };
mongoConnect.js
import { MongoClient } from "mongodb"; if (!process.env.MONGO_URL) { throw new Error('Invalid/Missing environment variable: "MONGODB_URI"'); } const uri = process.env.MONGO_URL; const options = {}; let client; let clientPromise; if (process.env.NODE_ENV === "development") { if (!global._mongoClientPromise) { client = new MongoClient(uri, options); global._mongoClientPromise = client.connect(); } clientPromise = global._mongoClientPromise; } else { client = new MongoClient(uri, options); clientPromise = client.connect(); } export default clientPromise;
错误信息
登录失败,收到意外服务器错误提示,CredentialsProvider的authorize处理器疑似数据库访问异常。
已尝试操作
- 反复检查数据库连接,禁用MongoDB Adapter时连接正常;
- 尝试过MongoDB Adapter的多种实现方式,确保数据库访问正常。
解决方案
问题根源在于同时使用mongoose和MongoClient两个独立的数据库连接客户端,导致连接冲突,且authorize函数内重复建立mongoose连接加剧了问题。以下是修复步骤:
1. 统一数据库连接方式
移除authorize函数内的mongoose.connect调用,直接使用已有的clientPromise进行数据库操作,避免连接冲突:
修改auth.js中的authorize函数:
async authorize(credentials, req) { const email = credentials?.email; const password = credentials?.password; // 使用已初始化的MongoClient连接 const client = await clientPromise; const db = client.db(); // 查询MongoDB Adapter默认使用的users集合 const user = await db.collection('users').findOne({ email }); if (!user) return null; // 验证密码 const passwordOk = bcrypt.compareSync(password, user.password); if (passwordOk) { // 返回符合NextAuth要求的用户对象,需将ObjectId转为字符串 return { id: user._id.toString(), email: user.email, name: user.name || '' }; } return null; }
2. 调整Session策略(可选)
若仍存在异常,可显式设置Session策略为jwt,避免Adapter的数据库Session与CredentialsProvider冲突:
在authOptions中添加:
session: { strategy: "jwt" }
3. 确保用户数据格式正确
- 确保MongoDB中
users集合内的账号文档包含password字段(需是bcrypt加密后的字符串); - Google登录创建的用户默认无
password字段,不影响Credentials登录,只需保证手动创建的账号有正确加密的密码。
4. 移除冗余的mongoose依赖(可选)
若不再使用mongoose模型,可直接移除mongoose相关导入和User模型,进一步避免连接冲突。
内容的提问来源于stack exchange,提问作者hossi
相关产品推荐
相关产品推荐

