【问题标题】:Check if Firebase Facebook user exists without creating a user starting from anonymous user检查 Firebase Facebook 用户是否存在而不从匿名用户开始创建用户
【发布时间】:2018-11-13 07:33:02
【问题描述】:

在 Firebase 中,我需要在不创建用户的情况下检查 Facebook 用户是否存在。最初,用户是匿名的,他们尝试使用 Facebook 登录。如果 Facebook 帐户尚未链接到我系统中的用户,我希望此操作失败。它不会链接到当前用户,因为他们是匿名的,

如果我使用 Auth.signInAndRetrieveDataWithCredential,我预计会出现“auth/user-not-found”错误,但只是简单地创建了用户。这是错误还是预期?

let credential = firebase.auth.FacebookAuthProvider.credential(
        event.authResponse.accessToken)
    firebase.auth().signInAndRetrieveDataWithCredential(credential).then( (userCredential) => {
        let user = userCredential.user
        app.debug("DEBUG: Existing user signed in:"+user.uid)
        this.loginSuccess(user)
    }).catch( (err) => {
        app.error("ERROR re-signing in:"+err.code)
        $("#login_status_msg").text(err)
    })

如果我使用 User.reauthenticateAndRetrieveDataWithCredential 代替,我会收到错误“auth/user-mismatch”,这是有道理的,因为用户当前是匿名的。但是,如果凭据不存在,我预计可能会抛出“auth/user-not-found”,但这不会发生。

我没有找到一种方法来获取我的匿名用户,让他们使用 Facebook 登录,然后查看其他用户是否已链接到该 Facebook 凭据,如果该用户不存在则不创建该用户。

如果您想知道为什么?我的情况是: 系统允许匿名用户

  1. 用户登录,然后通过注册 Facebook 转换为登录用户。
  2. 应用卸载
  3. 应用重新安装
  4. 用户启动应用程序,最初是匿名的。
  5. 他们再次尝试使用 Facebook 登录。在这一点上,如果他们还没有用户,我想阻止他们创建用户。如果他们已经有用户 ID,则代码可以正常工作并将他们的匿名帐户 ID 更改为原始用户 ID,这很好。

【问题讨论】:

    标签: javascript facebook firebase firebase-authentication


    【解决方案1】:

    我为解决此问题所做的工作是保存getCurrentAccessToken 返回的userID 字段,而不依赖于对linkAndRetrieveDataWithCredential 的调用失败并使用catch 块登录现有用户。

    const { userID } = data;
    this.props.setFacebookId(userID); // saves the userID on the server
    

    我可以稍后在用户下次注册 facebook 时检查此 userID 是否已经存在。

    【讨论】:

      【解决方案2】:

      我找到了解决办法!实现起来并不太难,但看起来确实很老套。

      所以我们知道,当使用signInAndRetrieveDataWithCredential(cred) 进行facebook 登录时,会创建帐户即使它还不存在。 要解决这个问题,我们需要确保处理以下三个事情:

      1. 检测帐户是否为新帐户
      2. 删除由 firebase 创建的当前帐户
      3. 抛出错误以退出当前流程并返回到之前的任何位置。

      我刚刚实现并测试了这个解决方案,它似乎工作得很好:

      // ... do your stuff to do fb login, get credential, etc:
      const userInfo = await firebase.auth().signInAndRetrieveDataWithCredential(credential)
      
      // userInfo includes a property to check if the account is new:
      const isNewUser = _.get(userInfo, 'additionalUserInfo.isNewUser', true)
      
      // FIRST, delete the account we just made.
      // SECOND, throw an error (or otherwise escape the current context.
      if (isNewUser) {
        firebase.auth().currentUser.delete()
        throw new Error('Couldn\'t find an existing account.')
      }
      
      // If the user already exists, just handle normal login
      return userInfo.user
      

      我这样做的原因是为了确保用户必须在我的应用程序中完成“创建帐户流程”。您的案例也很容易实现,如下所示:

      let credential = firebase.auth.FacebookAuthProvider.credential(event.authResponse.accessToken)
      
      firebase.auth().signInAndRetrieveDataWithCredential(credential)
        .then(userCredential => {
          const isNewUser = userCredential.additionalUserInfo.isNewUser
          if (isNewUser) {
            firebase.auth().currentUser.delete()
            // The following error will be handled in your catch statement
            throw new Error("Couldn't find an existing account.")
          }
          // Otherwise, handle login normally:
          const user = userCredential.user
          app.debug("DEBUG: Existing user signed in:"+user.uid)
          this.loginSuccess(user)
        }).catch( (err) => {
          app.error("ERROR re-signing in:"+err.code)
          $("#login_status_msg").text(err)
        })
      

      【讨论】:

        【解决方案3】:

        您可以使用fetchSignInMethodsForEmail 方法检查特定电子邮件是否已与特定提供商关联。这样做您将能够检查与您的用户关联的电子邮件的SighInMethods 是否包含Facebook.com

        我将在下面的示例中向您展示我如何在我的应用程序中管理这些案例。我在我的代码上使用了 RxJavaWrapper,但你会明白如何管理它的要点:

         RxFirebaseAuth.fetchSignInMethodsForEmail(authInstance, email)
                        .flatMap { providerResult ->
                            if (!providerResult.signInMethods!!.contains(credential.provider)) {
                                return@flatMap Maybe.error<AuthResult>(ProviderNotLinkedException(credential.provider))
                            } else {
                                return@flatMap RxFirebaseAuth.signInWithCredential(authInstance, credential)
                            }
                        }
                        .subscribe({ authResult ->
                          //Manage success
                        }, { error ->
                          //Manage error
                        })
        
        • 首先我检查与用户电子邮件关联的提供商(您可以从提供商处检索)
        • 如果 SignInMethods 列表包含我的凭据提供程序,我会抛出一个错误,如果没有,我会调用我的 signInWithCredential 方法来创建用户。
        • 继续您的工作流程。

        【讨论】:

        • 谢谢弗朗西斯科,但我不认为这对我有用。用户从匿名开始。但他们的 Facebook 帐户可能与 Firebase 中的其他用户相关联。当他们匿名时,我没有任何电子邮件给他们......他们只需要使用 Facebook 登录,然后 Firebase 告诉我他们的 Facebook 帐户与另一个 UserId 相关联,我的代码将它们切换到该 UserId。
        • 此解决方案的另一个问题是并非所有 Facebook 帐户都带有电子邮件。目前,我们的应用程序只有大约 50 个用户,并且有一些没有电子邮件的 Facebook 帐户。
        【解决方案4】:

        你可以使用linkAndRetrieveDataWithCredential:

        let credential = firebase.auth.FacebookAuthProvider.credential(
            event.authResponse.accessToken);
        anonymousUser.linkAndRetrieveDataWithCredential(credential).then( (userCredential) => {
          // Firebase Auth only allows linking a credential if it is not
          // already linked to another account.
          // Now the anonymous account is upgraded to a permanent Facebook account.
        }).catch( (err) => {
          // Check for code: auth/credential-already-in-use
          // When this error is returned, it means the credential is already
          // used by another account. 
        })
        

        【讨论】:

        • 感谢 bojeil,感谢您的建议。问题是如果尚未链接,我不想自动升级到永久 Facebook 帐户。这就是挑战。我想检查,但如果帐户尚不存在,则不要关联该帐户。
        猜你喜欢
        • 2021-02-22
        • 2016-07-26
        • 1970-01-01
        • 1970-01-01
        • 2020-05-11
        • 1970-01-01
        • 2018-11-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多