NextAuth使用数据库适配器时的凭证登录问题求助
NextAuth 凭证登录与GoogleProvider兼容问题解决
问题根源
启用MongoDBAdapter时,NextAuth默认会话策略为database,但CredentialsProvider并不适配数据库会话模式,导致凭证登录失败。切换到jwt策略后,若未配置对应的JWT与会话回调,GoogleProvider无法正确序列化用户信息到JWT中,进而导致第三方登录失效。
解决步骤
- 固定会话策略为JWT,显式声明
session: { strategy: "jwt" } - 配置JWT回调:在
jwt回调中添加用户关键信息(如ID、邮箱),确保JWT令牌包含完整用户标识 - 配置会话回调:将JWT中的用户信息映射到会话对象,保证前端能正确获取用户数据
- 优化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
相关产品推荐
相关产品推荐

