NextAuth集成GoogleProvider时session回调无法获取用户信息
问题分析与解决方案
核心问题
你的问题出在Session策略未显式配置以及JWT回调未完整保留用户信息,导致Session回调中无法正确获取用户邮箱等数据,最终客户端useSession拿不到有效信息。
具体修复步骤
1. 显式配置Session策略为JWT
当使用MongoDB Adapter时,NextAuth默认会采用database Session策略,这会导致JWT回调仅在首次登录时触发,后续请求的Session数据直接从数据库读取,此时你的Session回调中直接将session.user赋值为token会出现数据缺失或undefined。
需要在authOptions中添加session配置:
session: { strategy: "jwt", // 强制使用JWT策略,确保JWT和Session回调协同工作 maxAge: 30 * 24 * 60 * 60, // 可选:设置Session有效期,默认30天 },
2. 完善JWT回调,保留完整用户信息
你的JWT回调仅添加了accessToken和id,但未将用户的邮箱、名称等核心信息存入Token,导致后续Session回调中Token没有这些数据。修改JWT回调:
async jwt({ token, account, user }) { // 首次登录时(account和user存在),将用户信息合并到Token if (account && user) { return { ...token, id: user.id, email: user.email, name: user.name, picture: user.picture, accessToken: await SignToken(user.email as string), }; } // 非首次登录,直接返回现有Token return token; },
3. 修正Session回调,正确映射用户数据
不要直接将session.user替换为token,而是将Token中的字段逐一映射到session.user,保证Session结构符合NextAuth的默认规范:
async session({ session, token }) { if (session.user) { // 将Token中的用户信息赋值给Session.user session.user.id = token.id as string; session.user.email = token.email as string; session.user.name = token.name as string; session.user.picture = token.picture as string; session.user.accessToken = token.accessToken as string; } return session; },
4. 可选:确保GoogleProvider权限范围正确
虽然默认情况下GoogleProvider会请求email和profile权限,但显式声明可以避免权限缺失问题:
GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID!!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!!, authorization: { params: { scope: "openid email profile", // 显式请求邮箱和基础资料权限 }, }, })
完整修正后的服务端代码
export const authOptions: NextAuthOptions = { adapter: MongoDBAdapter(clientPromise), // 新增Session策略配置 session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60, }, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID!!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!!, authorization: { params: { scope: "openid email profile", }, }, }), ], callbacks: { async jwt({ token, account, user }) { if (account && user) { return { ...token, id: user.id, email: user.email, name: user.name, picture: user.picture, accessToken: await SignToken(user.email as string), }; } return token; }, async session({ session, token }) { if (session.user) { session.user.id = token.id as string; session.user.email = token.email as string; session.user.name = token.name as string; session.user.picture = token.picture as string; session.user.accessToken = token.accessToken as string; } return session; }, }, };
验证结果
修改后重新启动服务,客户端通过useSession获取的session.user会包含email、id、name等完整信息,控制台输出的session数据也会正常显示用户邮箱。
内容的提问来源于stack exchange,提问作者Captai-N
相关产品推荐
相关产品推荐

