L’authentification utilisant Facebook dans un premier temps puis Google provoque une erreur dans Firebase pour Android




facebook-login firebase-authentication (4)

Si je comprends bien d'après Firebase Docs , si un utilisateur authentifie son compte avec un identifiant, il doit se connecter strictement en utilisant le même identifiant si celui-ci n'est pas encore lié à un autre.

En d'autres termes, si je crée un compte à l'aide de la connexion Google, puis (après la déconnexion), essaie de me connecter avec les informations d'identification Facebook en utilisant le même courrier électronique que celui utilisé pour les informations d'identification Google, je devrais voir cette exception dans logcat:

"Un compte existe déjà avec la même adresse électronique, mais différentes informations d'identification pour la connexion. Connectez-vous à l'aide d'un fournisseur associé à cette adresse électronique."

Et oui, je reçois cette exception sans surprise. Mais si je crée un compte en utilisant Facebook, puis que j'essaie de me connecter avec les informations d'identification Google, le fournisseur de ce compte (Facebook) est converti en Google. Cette fois, l'authentification n'échoue pas mais ce n'est pas le résultat attendu. Je souhaite associer chaque utilisateur à un identifiant spécifique en quelque sorte. Comment dois-je résoudre ce problème? Vous pouvez voir le code ci-dessous:

public class SignInActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener,
        View.OnClickListener {

    private static final String TAG = "SignInActivity";
    private static final int RC_SIGN_IN = 9001;

    private GoogleApiClient mGoogleApiClient;
    private FirebaseAuth mFirebaseAuth;
    private FirebaseAuth.AuthStateListener mFirebaseAuthListener;

    private CallbackManager mCallbackManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_sign_in);

        // Facebook Login
        FacebookSdk.sdkInitialize(getApplicationContext());
        mCallbackManager = CallbackManager.Factory.create();

        LoginButton mFacebookSignInButton = (LoginButton) findViewById(R.id.facebook_login_button);
        mFacebookSignInButton.setReadPermissions("email", "public_profile");

        mFacebookSignInButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
            @Override
            public void onSuccess(LoginResult loginResult) {
                Log.d(TAG, "facebook:onSuccess:" + loginResult);
                firebaseAuthWithFacebook(loginResult.getAccessToken());
            }

            @Override
            public void onCancel() {
                Log.d(TAG, "facebook:onCancel");
            }

            @Override
            public void onError(FacebookException error) {
                Log.d(TAG, "facebook:onError", error);
            }
        });

        // Google Sign-In
        // Assign fields
        SignInButton mGoogleSignInButton = (SignInButton) findViewById(R.id.google_sign_in_button);

        // Set click listeners
        mGoogleSignInButton.setOnClickListener(this);

        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.default_web_client_id))
                .requestEmail()
                .build();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();

        // Initialize FirebaseAuth
        mFirebaseAuth = FirebaseAuth.getInstance();

        mFirebaseAuthListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user != null) {
                    // User is signed in
                    Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
                } else {
                    // User is signed out
                    Log.d(TAG, "onAuthStateChanged:signed_out");
                }
            }
        };
    }

    @Override
    public void onStart() {
        super.onStart();
        mFirebaseAuth.addAuthStateListener(mFirebaseAuthListener);
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mFirebaseAuthListener != null) {
            mFirebaseAuth.removeAuthStateListener(mFirebaseAuthListener);
        }
    }

    private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
        Log.d(TAG, "firebaseAuthWithGooogle:" + acct.getId());
        AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
        mFirebaseAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

                        // If sign in fails, display a message to the user. If sign in succeeds
                        // the auth state listener will be notified and logic to handle the
                        // signed in user can be handled in the listener.
                        if (!task.isSuccessful()) {
                            Log.w(TAG, "signInWithCredential", task.getException());
                            Toast.makeText(SignInActivity.this, "Authentication failed.",
                                    Toast.LENGTH_SHORT).show();
                        } else {
                            startActivity(new Intent(SignInActivity.this, MainActivity.class));
                            finish();
                        }
                    }
                });
    }

    private void firebaseAuthWithFacebook(AccessToken token) {
        Log.d(TAG, "handleFacebookAccessToken:" + token);

        final AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
        mFirebaseAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

                        // If sign in fails, display a message to the user. If sign in succeeds
                        // the auth state listener will be notified and logic to handle the
                        // signed in user can be handled in the listener.
                        if (!task.isSuccessful()) {
                            Log.w(TAG, "signInWithCredential", task.getException());
                            Toast.makeText(SignInActivity.this, "Authentication failed.",
                                    Toast.LENGTH_SHORT).show();
                        }

                        else {
                            startActivity(new Intent(SignInActivity.this, MainActivity.class));
                            finish();
                        }
                    }
                });
    }

    /*
    private void handleFirebaseAuthResult(AuthResult authResult) {
        if (authResult != null) {
            // Welcome the user
            FirebaseUser user = authResult.getUser();
            Toast.makeText(this, "Welcome " + user.getEmail(), Toast.LENGTH_SHORT).show();

            // Go back to the main activity
            startActivity(new Intent(this, MainActivity.class));
        }
    }
    */

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.google_sign_in_button:
                signIn();
                break;
            default:
                return;
        }
    }

    private void signIn() {
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, RC_SIGN_IN);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        mCallbackManager.onActivityResult(requestCode, resultCode, data);

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
        if (requestCode == RC_SIGN_IN) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (result.isSuccess()) {
                // Google Sign In was successful, authenticate with Firebase
                GoogleSignInAccount account = result.getSignInAccount();
                firebaseAuthWithGoogle(account);
            } else {
                // Google Sign In failed
                Log.e(TAG, "Google Sign In failed.");
            }
        }
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        // An unresolvable error has occurred and Google APIs (including Sign-In) will not
        // be available.
        Log.d(TAG, "onConnectionFailed:" + connectionResult);
        Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
    }
}

Pour minimiser les clics de l'interface utilisateur de connexion sans compromettre la sécurité du compte, Firebase Authentication utilise le concept de «fournisseur de confiance», le fournisseur d'identité étant également le fournisseur de service de messagerie. Par exemple, Google est le fournisseur de confiance pour les adresses @ gmail.com, Yahoo est le fournisseur de confiance pour les adresses @ yahoo.com et Microsoft pour les adresses @ outlook.com.

En mode "Un compte par adresse électronique", Authentification Firebase tente de lier le compte en fonction de l'adresse électronique. Si un utilisateur se connecte à partir d'un fournisseur de confiance, l'utilisateur se connecte immédiatement au compte car nous savons qu'il possède l'adresse e-mail.

S'il existe un compte existant avec la même adresse électronique mais créé avec des informations d'identification non approuvées (par exemple, un fournisseur ou un mot de passe non approuvé), les informations d'identification précédentes sont supprimées pour des raisons de sécurité. Un hameçonneur (qui n'est pas le propriétaire de l'adresse de messagerie) peut créer le compte initial - la suppression des informations d'identification initiales empêcherait le phishing d'accéder au compte par la suite.

Jin Liu


Autoriser la création de plusieurs comptes avec la même adresse e-mail est ce que vous recherchez.

Cela fonctionne très bien UNIQUEMENT si vous vérifiez l’email dans votre backend et c’est la référence pour vos utilisateurs. Si vous utilisez l'ID Firebase, cela ne permettra pas de conserver des utilisateurs uniques.


J'ai eu le même problème, tout ce que vous avez à faire est d'aller dans la console Firebase, puis dans la catégorie "Authentification", supprimez l'utilisateur de votre choix.

Cela fonctionne pour moi.


J'ai finalement fini avec cette logique:

Si l'utilisateur tente de se connecter à Facebook, alors qu'il existe déjà (avec le fournisseur Google), il contient déjà un courrier électronique et que cette erreur se produit:

"Un compte existe déjà avec la même adresse électronique, mais différentes informations d'identification pour la connexion. Connectez-vous à l'aide d'un fournisseur associé à cette adresse électronique."

Donc, il suffit de demander à l'utilisateur de se connecter à l'aide de Google (et ensuite de lier silencieusement Facebook à un compte existant)







google-authentication