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

Next.js 15中NextAuth谷歌登录结合Sanity的问题排查——回调异常与用户资料创建问题

Next.js 15中NextAuth谷歌登录结合Sanity的问题排查——回调异常与用户资料创建问题

兄弟,我看你这问题核心就是加了signIn回调后Google登录就炸了,去掉就正常,大概率是回调里的逻辑踩了几个隐形坑,我帮你一一捋清楚:

1. 最可能的元凶:Google Profile字段完全搞反了!

你在signIn回调里解构的profile.id、profile.login、profile.bio,这些字段Google OAuth根本不返回啊!
NextAuth的Google Provider返回的Profile结构里:

  • 用户的唯一Google ID是profile.sub,不是id
  • 根本没有login这个字段(那是GitHub的专属字段!)
  • bio对应的是profile.aboutMe,而且得额外申请权限才能拿到,默认是没有的

你拿不存在的字段去查Sanity、创建文档,肯定会报错,导致signIn回调直接失败,登录流程直接卡壳。

临时排查方案:先在回调里打日志看真实的Profile结构,确认字段:

async signIn({ user, profile }) {
  console.log("真实的Google Profile:", profile);
  console.log("NextAuth封装的User:", user);
  // 先注释其他代码,返回true看看能不能正常登录
  return true;
}

2. Sanity写入的两个隐形坑

(1)Write Client权限不足

你的writeClient有没有配置正确的Sanity写入Token?这个Token必须有创建author文档的权限,不然创建操作会直接抛错,导致回调失败。

(2)Schema字段约束

如果你的Sanity author Schema里,username、id是必填字段,而你传了undefined(比如用了不存在的login字段),Sanity会直接拒绝创建,回调自然就失败了。

3. 给你修正后的完整可用代码

我把所有坑都填上了,你直接替换试试:

import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import { client } from "./sanity/lib/client";
import { AUTHOR_BY_GOOGLE_ID } from "./sanity/lib/queries";
import { writeClient } from "./sanity/lib/write-client";

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    Google({
      // 如果需要获取用户的aboutMe(即你要的bio),必须加这个权限 scope
      authorization: {
        params: {
          scope: "openid email profile https://www.googleapis.com/auth/userinfo.profile"
        }
      }
    })
  ],
  callbacks: {
    async signIn({ user, profile }) {
      // 拿到正确的Google用户唯一ID
      const googleId = profile.sub;
      if (!googleId) {
        console.error("无法获取Google用户唯一ID");
        return false;
      }

      try {
        // 查询Sanity里是否已有该用户
        const existingUser = await client
          .withConfig({ useCdn: false })
          .fetch(AUTHOR_BY_GOOGLE_ID, { id: googleId });

        // 不存在则创建新用户
        if (!existingUser) {
          // 用Google真实返回的字段填充,避免undefined
          const newAuthor = {
            _type: "author",
            id: googleId,
            name: user.name || `${profile.givenName} ${profile.familyName}`,
            // 用用户的名作为默认用户名,防止空值
            username: profile.givenName || user.name?.split(" ")[0] || "unknown-user",
            email: user.email,
            image: user.image || profile.picture,
            // Google的bio是aboutMe字段,没有则留空
            bio: profile.aboutMe || "",
          };
          await writeClient.create(newAuthor);
          console.log("新用户已成功写入Sanity:", newAuthor);
        }
        return true;
      } catch (error) {
        // 捕获错误才能精准定位问题
        console.error("登录回调执行失败:", error);
        return false;
      }
    },
    async jwt({ token, account, profile }) {
      if (account && profile) {
        const googleId = profile.sub;
        const user = await client
          .withConfig({ useCdn: false })
          .fetch(AUTHOR_BY_GOOGLE_ID, { id: googleId });
        token.id = user?._id;
      }
      return token;
    },
    async session({ session, token }) {
      Object.assign(session, { id: token.id });
      return session;
    },
  }
});

最后还要检查这两点

  1. 你的AUTHOR_BY_GOOGLE_ID查询是不是正确的?比如查询条件是id == $id,要和你传入的googleId完全对应
  2. Sanity的author Schema里,id字段是不是设置为string类型,并且开启了唯一值约束?

备注:内容来源于stack exchange,提问作者M3nnoun

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:44:39