How to handle FirebaseAuthUserCollisionException

徘徊边缘 提交于 2020-02-13 03:03:40

问题


I started getting a FirebaseAuthUserCollisionException exception when I try to sign in with Facebook in my Android application.

com.google.firebase.auth.FirebaseAuthUserCollisionException: An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address.

I am using Firebase to handle the registration and Facebook to deliver a "one-click" login method, using a com.facebook.login.widget.LoginButton view as a trigger.

These sign-in method was already working. I was able to register a account with Facebook, and use the same method to log-in this account. But now have start to throwing this exception.

Here is the code where I register a account from Facebook and proceed with login:

private void handleFacebookAccessToken(AccessToken token) {
    final ProgressDialog dialog = new ProgressDialog(this);
    dialog.show(getString(R.string.dialog_wait));
    firebaseAuth.signInWithCredential(FacebookAuthProvider.getCredential(token.getToken()))
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        dialog.close();
                        registerNewUserFromSocialLogin(firebaseAuth.getCurrentUser());
                    } else {
                        if(task.getException() instanceof FirebaseAuthUserCollisionException) {

                            //TODO: handle sign-in with different credentials

                        } else {
                            dialog.close();
                            LoginManager.getInstance().logOut();
                            Toast.makeText(LoginActivity.this,
                                    R.string.error_login,
                                    Toast.LENGTH_SHORT).show();
                        }
                    }
                }
            });
}

And my Gradle file with current use library:

compile 'com.google.firebase:firebase-auth:10.2.1'
compile 'com.facebook.android:facebook-android-sdk:[4,5)'

So my problem is: I don't know how to handle FirebaseAuthUserCollisionException exception.

None of the solutions in StackOverflow or Firebase Documentation help me. I am looking for a solution that is able to login the user although the duplicated credential, to stil deliver the "one-click" login method.


回答1:


You will get that error when the user had previously signed in with the same email using a different provider. For example, the user signs in with email user@gmail.com using Google. The user then tries to sign in with the same email but using Facebook. The Firebase Auth backend will return that error (account exists with different credential). In that case, you should use the fetchProvidersForEmail to look up the existing providers associated with email user@gmail.com, in this case google.com. You signInWithCredential to the existing google account to prove ownership of that account, and then linkWithCredential the Facebook credential the user originally was trying to sign in with. This merges both accounts so in the future the user can sign in with either.

This happens when you use the single accounts per email. If you want to allow different accounts per email, you can switch to multiple accounts per email in the Firebase console.

Here is an example:

mAuth.signInWithCredential(authCredential)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
        @Override
        public void onComplete(@NonNull Task<AuthResult> task) {
            // Account exists with different credential. Assume the developer wants to
            // continue and link new credential to existing account.
            if (!task.isSuccessful() &&
                task.getException() instanceof FirebaseAuthUserCollisionException) {
                FirebaseAuthUserCollisionException exception =
                        (FirebaseAuthUserCollisionException)task.getException();
                if (exception.getErrorCode() == 
                    ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL) {
                    // Lookup existing account’s provider ID.
                    mAuth.fetchProvidersForEmail(existingAcctEmail)
                       .addOnCompleteListener(new OnCompleteListener<ProviderQueryResult> {
                          @Override
                          public void onComplete(@NonNull Task<ProviderQueryResult> task) {
                            if (task.isSuccessful()) {
                              if (task.getResult().getProviders().contains(
                                      EmailAuthProvider.PROVIDER_ID)) {
                                // Password account already exists with the same email.
                                // Ask user to provide password associated with that account.
                                ... 
                                // Sign in with email and the provided password.
                                // If this was a Google account, call signInWithCredential instead.
                                mAuth.signInWithEmailAndPassword(existingAcctEmail, password)
                                  addOnCompleteListener(new OnCompleteListener<AuthResult> {
                                    @Override
                                    public void onComplete(@NonNull Task<AuthResult> task) {
                                      if (task.isSuccessful()) { 
                                        // Link initial credential to existing account.
                                        mAuth.getCurrentUser().linkWithCredential(authCredential);
                                      }
                                    }
                                  });
                              }
                            }
                          }
                        });
            }
        }
    });



回答2:


The easiest approach is just to check up front - I try to sign in with any acquired credential first, and only create a new account when it does not exist

AuthCredential credential //... Obtain whatever

auth.signInWithCredential(credential).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
    @Override
    public void onComplete(@NonNull Task<AuthResult> task) {
        if (task.isSuccessful()) {
            Log.d(TAG, "Credential login succeeded (no new account)");
            ... //success logic
        } else {
            Log.e(TAG, "Failed to login with credential, attempting a new account instead. (" + task.getException() + ")");
            auth.getCurrentUser().linkWithCredential(credential).addOnCompleteListener(getActivity(), ...); //use the same callback as you usually would
        }
    }
});


来源:https://stackoverflow.com/questions/46322998/how-to-handle-firebaseauthusercollisionexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!