Firebase JS API 身份验证 - 帐户存在于不同的凭据

新手上路,请多包涵

我们在尝试解决这个问题时遇到了真正的问题,因此希望得到一些 Firebase 的帮助/那些已经解决了同样问题的人。

该应用程序是 React Native (0.43.2) 并使用 Firebase JS API(最新)

我们提供 Facebook 和 Google 身份验证。工作正常。

但是,如果用户:

  1. 使用 Facebook 登录(可以)
  2. 稍后,使用 Google 登录(也可以)
  3. 稍后,尝试使用 Facebook 登录 - BOOM!不太好,Firebase 返回此错误:

auth/account-exists-with-different-credential

通过阅读文档和一些关于 SO 的帖子,我们认为以下内容是正确的,但显然不正确,因为我们得到了相同的身份验证错误。

 ...error returned by Firebase auth after trying Facebook login...

const email = error.email;
const pendingCred = error.credential;

firebase.auth().fetchProvidersForEmail(email)
.then(providers => {
   //providers returns this array -> ["google.com"]
   firebase.auth().signInWithCredential(pendingCred)
   .then(result => {
       result.user.link(pendingCred)
   })
   .catch(error => log(error))

对 signInWithCredential 的调用抛出相同的错误 auth/account-exists-with-different-credential

任何人都可以帮助指出我们在这个实现中做错了什么吗?非常感激。

原文由 ajonno 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 898
2 个回答

发生的事情是 Firebase 对所有电子邮件强制使用相同的帐户。由于您已经拥有同一电子邮件的 Google 帐户,因此您需要将该 Facebook 帐户链接到 Google 帐户,以便用户可以访问相同的数据,并且下次能够使用 Google 或 Facebook 登录同一帐户。

您的代码段中的问题是您正在使用相同的凭据进行签名和链接。修改如下。当您收到错误“auth/account-exists-with-different-credential”时,该错误将包含 error.email 和 error.credential(Facebook OAuth 凭证)。您需要先查找 error.email 以获取现有的提供者。

 firebase.auth().fetchProvidersForEmail(error.email)
  .then(providers => {
    //providers returns this array -> ["google.com"]
    // You need to sign in the user to that google account
    // with the same email.
    // In a browser you can call:
    // var provider = new firebase.auth.GoogleAuthProvider();
    // provider.setCustomParameters({login_hint: error.email});
    // firebase.auth().signInWithPopup(provider)
    // If you have your own mechanism to get that token, you get it
    // for that Google email user and sign in
    firebase.auth().signInWithCredential(googleCred)
      .then(user => {
        // You can now link the pending credential from the first
        // error.
        user.linkWithCredential(error.credential)
      })
      .catch(error => log(error))

原文由 bojeil 发布,翻译遵循 CC BY-SA 3.0 许可协议

我发现 Firebase 选择此行为作为默认行为很奇怪且不方便,而且解决方案很重要。这是截至撰写本文时基于@bojeil 的回答的 Firebase 的完整和更新的解决方案。

 function getProvider(providerId) {
  switch (providerId) {
    case firebase.auth.GoogleAuthProvider.PROVIDER_ID:
      return new firebase.auth.GoogleAuthProvider();
    case firebase.auth.FacebookAuthProvider.PROVIDER_ID:
      return new firebase.auth.FacebookAuthProvider();
    case firebase.auth.GithubAuthProvider.PROVIDER_ID:
      return new firebase.auth.GithubAuthProvider();
    default:
      throw new Error(`No provider implemented for ${providerId}`);
  }
}

const supportedPopupSignInMethods = [
  firebase.auth.GoogleAuthProvider.PROVIDER_ID,
  firebase.auth.FacebookAuthProvider.PROVIDER_ID,
  firebase.auth.GithubAuthProvider.PROVIDER_ID,
];

async function oauthLogin(provider) {
  try {
    await firebase.auth().signInWithPopup(provider);
  } catch (err) {
    if (err.email && err.credential && err.code === 'auth/account-exists-with-different-credential') {
      const providers = await firebase.auth().fetchSignInMethodsForEmail(err.email)
      const firstPopupProviderMethod = providers.find(p => supportedPopupSignInMethods.includes(p));

      // Test: Could this happen with email link then trying social provider?
      if (!firstPopupProviderMethod) {
        throw new Error(`Your account is linked to a provider that isn't supported.`);
      }

      const linkedProvider = getProvider(firstPopupProviderMethod);
      linkedProvider.setCustomParameters({ login_hint: err.email });

      const result = await firebase.auth().signInWithPopup(linkedProvider);
      result.user.linkWithCredential(err.credential);
    }

    // Handle errors...
    // toast.error(err.message || err.toString());
  }
}

原文由 Dominic 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题