首页 > 解决方案 > 使用密码身份验证向用户添加电子邮件链接身份验证时,linkWithCredential 会引发提供程序已链接的错误

问题描述

我有一个使用电子邮件/密码进行身份验证的用户。当我尝试使用credentialWithLinkand为用户添加电子邮件链接身份验证时linkWithCredential,出现错误:

code: "auth/provider-already-linked"
message: "User can only be linked to one identity for the given provider."

错误消息告诉我,我无法为用户添加电子邮件链接身份验证,因为用户已经使用密码通过电子邮件提供商进行了身份验证。

那么使用密码身份验证为现有用户添加电子邮件链接身份验证的正确方法是什么?

这是我尝试抛出“auth/provider-already-linked”错误的方法:

  1. 使用电子邮件和密码创建用户。发送电子邮件验证
const userCred = await firebase
  .auth()
  .createUserWithEmailAndPassword(email, password);

if (userCred) {
  const { user } = userCred;
  await user.sendEmailVerification());
}
  1. 验证邮件
await firebase.auth().applyActionCode(actionCode)
await firebase.auth().currentUser.reload()

此时,用户登录并fetchSignInMethodsForEmail返回['password']

const signInMethods = await firebase.auth().fetchSignInMethodsForEmail(email)

if (signInMethods) {
  console.log(signInMethods) // returns ['password']
}
  1. 将登录链接发送到电子邮件
await firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
window.localStorage.setItem('emailForSignIn', email)
  1. 确认登录链接
if (firebase.auth().isSignInWithEmailLink(href)) {
  let email = window.localStorage.getItem('emailForSignIn')
  if (!email) {
    email = window.prompt('Please provide your email for confirmation')
  }
  const credential = firebase.auth.EmailAuthProvider.credentialWithLink(
    email,
    window.location.href
  );
  firebase
    .auth()
    .currentUser.linkWithCredential(credential)
    .then((result) => {
      console.log('success linking with email link')
      window.localStorage.removeItem('emailForSignIn')
    })
    .catch((error) => {
      // Some error occurred.
      console.log('error linking with email link')
      console.log(error)
    })
}

由于我已经登录并与电子邮件提供商链接,因此调用firebase.auth.EmailAuthProvider.credentialWithLink会引发错误。

那么,如何emaillink为已经通过仅具有password登录方法的电子邮件提供商进行身份验证的用户添加登录方法?从错误消息中,我知道我不应该使用credentialWithLinkand linkWithCredential。那我该怎么办?

标签: firebasefirebase-authentication

解决方案


您正在尝试将使用电子邮件创建的帐户与另一个电子邮件链接。正如错误所说,“用户只能链接到给定提供者的一个身份。”。这意味着一个帐户只能将一个电子邮件、谷歌帐户、Facebook 等链接在一起。

如果您希望一个用户拥有多封电子邮件,那么您可能必须使用数据库。 在此处输入图像描述

如果您使用 Firestore,那么您可以像这样存储电子邮件,并在需要时进行如下查询:

userRef.where("emails", "array-contains", "emailEnteredByUser");

PS:用户只能使用他们最初用来创建帐户的主要电子邮件来登录或注册。

一种解决方法:您实际上可以依靠电子邮件链接身份验证来允许用户登录。当用户输入他们的电子邮件并单击登录时,您可以运行云功能(或您自己服务器中的功能)来生成登录链接,然后验证用户的文档是否包含他们输入的电子邮件,并使用Nodemailer 之类的东西来发送电子邮件他们是登录链接。

编辑: OP 假定密码和登录链接是不同的身份验证提供程序。如此处的文档中所述:

用户首次登录后,会创建一个新用户帐户并将其链接到凭据(即用户名和密码、电话号码或身份验证提供商信息),即用户登录时使用的凭据。因此,如果用户存在电子邮件,您仍然可以使用电子邮件链接。


推荐阅读