NextJS14+AuthJS社交登录:JWT认证后同步用户至MongoDB问题
解决NextJS14 AuthJS登录后服务器动作中无法获取已认证用户的问题
问题根源
你在服务器动作的finally块中调用auth()拿不到用户信息,是因为signIn执行完成后,新的Session Cookie还没写入响应,当前请求的auth()只能读取请求携带的旧Cookie,自然拿不到刚登录的用户数据。另外,finally块会在signIn无论成功失败都执行,逻辑上也不适合处理登录成功后的用户同步操作。
可行解决方案
1. 直接从signIn返回结果获取用户数据
在服务器动作中,将signIn的redirect参数设为false,这样signIn会返回包含用户信息的结果,不用依赖auth()就能拿到登录用户的详情,直接在此处完成MongoDB的检查与创建操作:
// 登录页的服务器动作 async function handleSocialLogin(provider: string) { // 关闭自动跳转,获取登录结果 const signInResult = await signIn(provider, { redirect: false }); if (signInResult?.user) { const { email, name, image } = signInResult.user; // 检查MongoDB中是否存在该邮箱 const existingUser = await db.collection('users').findOne({ email }); if (!existingUser) { // 不存在则创建新用户 await db.collection('users').insertOne({ email, name, image, createdAt: new Date(), }); } // 处理完成后跳转至应用首页 redirect('/'); } else { // 处理登录失败场景 return { error: '社交登录失败,请重试' }; } }
2. 利用AuthJS的jwt回调实现高效同步
这种方式更优雅,且只会在用户首次登录或JWT刷新时执行一次检查,避免重复操作,效率更高。在AuthJS配置的callbacks.jwt中处理用户同步逻辑:
// auth.ts 中的AuthOptions配置 export const authOptions: AuthOptions = { providers: [/* 你的社交登录提供商配置,如Google、GitHub等 */], session: { strategy: 'jwt' }, // 你当前使用的JWT策略 callbacks: { async jwt({ token, user }) { // user参数仅在首次登录时存在 if (user) { // 检查MongoDB中是否存在该用户 const existingUser = await db.collection('users').findOne({ email: user.email }); if (!existingUser) { // 创建新用户 const newUser = await db.collection('users').insertOne({ email: user.email, name: user.name, image: user.image, createdAt: new Date(), }); // 将新用户ID存入token,方便后续使用 token.userId = newUser.insertedId.toString(); } else { token.userId = existingUser._id.toString(); } } return token; }, // 可选:将用户ID同步到Session中,方便页面/服务器组件获取 async session({ session, token }) { if (session.user) { session.user.id = token.userId as string; } return session; }, }, // 其他配置... };
注意事项
- 不要在
finally块中处理用户同步:finally的执行时机不区分signIn成功失败,且当前请求无法获取新Session,逻辑和技术上都不适用。 - 选择第二种方案更符合AuthJS的设计逻辑,且能避免重复查询MongoDB,性能更优。
内容的提问来源于stack exchange,提问作者Rich
相关产品推荐
相关产品推荐

