检查Firebase Facebook用户是否存在,而不是从匿名用户

时间:2018-06-04 01:48:29

标签: javascript facebook firebase firebase-authentication

在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凭据而不创建用户(如果它不存在)。 / p>

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

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

4 个答案:

答案 0 :(得分:1)

我找到了解决方案!实施起来并不难,但是看起来确实很hack。

因此我们知道,使用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)
  })

答案 1 :(得分:0)

您可以使用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方法来创建用户。
  • 继续您的工作流程。

答案 2 :(得分:0)

You can use 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. 
})

答案 3 :(得分:0)

我为解决此问题而没有依靠对@echo off setlocal EnableExtensions DisableDelayedExpansion rem // Define constants here: set "_SOURCE=C:\Users\Test\Documents\Input" & rem // (absolute source path) set "_TARGET=C:\Users\Test\Documents\Output" & rem // (absolute target path) set "_PATTERN=*.*" & rem // (pure file pattern for input files) set "_FILEEXT=.mp3" & rem // (pure file extension of output files) pushd "%_TARGET%" || exit /B 1 for /F "delims=" %%F in (' cd /D "%_SOURCE%" ^&^& ^(rem/ list but do not copy: ^ ^& xcopy /L /S /Y /I ".\%_PATTERN%" "%_TARGET%" ^ ^| find ".\" ^& rem/ remove summary line; ^) ') do ( 2> nul mkdir "%%~dpF." rem // Set up the correct `ffmpeg` command line here: set "FFREPORT=file=C\:\\Users\\Test\\Documents\\Output\\ffreport-%%~F.log:level=32" "C:\ffmpeg\bin\ffmpeg.exe" -report -n -i "%_SOURCE%\%%~F" -vn -c:a libmp3lame -b:a 128k "%%~dpnF%_FILEEXT%" if not errorlevel 1 if exist "%%~dpnF%_FILEEXT%" del /f /q "%_SOURCE%\%%~F" ) popd endlocal pause 的调用失败并且使用catch块登录已经存在的用户的方法是保存{{1} }返回。

linkAndRetrieveDataWithCredential

我以后可以在用户下次登录Facebook时检查此userID是否已经存在。