在Next-Auth中,是否可以使用不同的提供商,但使用相同的电子邮件?

ee7vknir  于 2023-03-18  发布在  其他
关注(0)|答案(1)|浏览(151)

我正在使用next-auth构建一个nextjs应用程序。现在我已经登录谷歌,凭据和github。如果我登录谷歌,其中包含电子邮件“example@gmail.com“,然后我注销,如果我尝试登录github,但与帐户有相同的电子邮件“example@gmail.com”,我得到错误:O验证帐户未链接
在next-auth提供给我们的数据库模型中,用户与帐户的关系是一个数组,所以我认为这将是可能的,但喜欢与2个帐户的sabe用户。我忘了什么,或者这是默认行为?
我的[... nextAuth].ts代码

export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  const data = requestWrapper(req, res);
  return await NextAuth(...data);
};

export default handler;

export function requestWrapper(
  req: NextApiRequest,
  res: NextApiResponse
): [req: NextApiRequest, res: NextApiResponse, opts: NextAuthOptions] {
  const generateSessionToken = () => randomUUID();

  const fromDate = (time: number, date = Date.now()) =>
    new Date(date + time * 1000);

  const adapter = PrismaAdapter(prisma);

  const opts: NextAuthOptions = {
    // Include user.id on session
    adapter: adapter,
    pages: {
      signIn: "/login",
    },
    callbacks: {
      session({ session, user }) {
        console.log("AAAA");
        if (session.user) {
          session.user = user;
        }
        return session;
      },
      async signIn({ user, account, profile, email, credentials }) {
        // Check if this sign in callback is being called in the credentials authentication flow. If so, use the next-auth adapter to create a session entry in the database (SignIn is called after authorize so we can safely assume the user is valid and already authenticated).
        if (
          req.query.nextauth?.includes("callback") &&
          req.query.nextauth?.includes("credentials") &&
          req.method === "POST"
        ) {
          if (user) {
            const sessionToken = generateSessionToken();
            const sessionMaxAge = 60 * 60 * 24 * 30; //30Daysconst sessionMaxAge = 60 * 60 * 24 * 30; //30Days
            const sessionExpiry = fromDate(sessionMaxAge);

            await adapter.createSession({
              sessionToken: sessionToken,
              userId: user.id,
              expires: sessionExpiry,
            });

            const cookies = new Cookies(req, res);

            cookies.set("next-auth.session-token", sessionToken, {
              expires: sessionExpiry,
            });
          }
        }

        return true;
      },
    },
    jwt: {
      encode: async ({ token, secret, maxAge }) => {
        if (
          req.query.nextauth?.includes("callback") &&
          req.query.nextauth.includes("credentials") &&
          req.method === "POST"
        ) {
          const cookies = new Cookies(req, res);
          const cookie = cookies.get("next-auth.session-token");
          if (cookie) return cookie;
          else return "";
        }
        // Revert to default behaviour when not in the credentials provider callback flow
        return encode({ token, secret, maxAge });
      },
      decode: async ({ token, secret }) => {
        if (
          req.query.nextauth?.includes("callback") &&
          req.query.nextauth.includes("credentials") &&
          req.method === "POST"
        ) {
          return null;
        }

        // Revert to default behaviour when not in the credentials provider callback flow
        return decode({ token, secret });
      },
    },
    // Configure one or more authentication providers
    secret: process.env.NEXTAUTH_SECRET,
    // debug: true,
    providers: [
      GithubProvider({
        clientId: process.env.GITHUB_ID as string,
        clientSecret: process.env.GITHUB_SECRET as string,
        profile(profile, token) {
          return {
            id: profile.id.toString(),
            name: profile.name || profile.login,
            image: profile.avatar_url,
            email: profile.email,
            role: Role.USER,
          };
        },
      }),
      GoogleProvider({
        clientId: process.env.GOOGLE_ID as string,
        clientSecret: process.env.GOOGLE_SECRET as string,
        authorization: {
          params: {
            prompt: "consent",
            access_type: "offline",
            response_type: "code",
          },
        },
      }),
      CredentialProvider({
        name: "CredentialProvider",
        credentials: {
          email: { label: "Email", type: "text", placeholder: "" },
          password: { label: "Password", type: "password" },
        },
        async authorize(credentials: any, _req): Promise<any | null> {
          const userInputs = {
            email: credentials.email,
            password: credentials.password,
          };

          const { user } = await loginCredentials(userInputs);

          if (user) {
            return user;
          } else {
            return null;
          }
        },
      }),
    ],
  };

  return [req, res, opts];
}
nbysray5

nbysray51#

对我来说,解决这个问题的方法是添加allowDangerousEmailAccountLinking: true,它看起来像这样:

providers: [
    GithubProvider({
      clientId: env.GITHUB_CLIENT_ID,
      clientSecret: env.GITHUB_CLIENT_SECRET,
      allowDangerousEmailAccountLinking: true,
    }),
    GoogleProvider({
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
      allowDangerousEmailAccountLinking: true,
    }),
   ]

这样做应该可以解决大多数关于帐户链接的错误,但我肯定很乐意听到有人提出了更好的解决方案。
更多关于这一点:https://next-auth.js.org/configuration/providers/oauth#allowdangerousemailaccountlinking-option

相关问题