Si je comprends bien des Firebase Docs , si un utilisateur authentifie son compte avec un identifiant, il doit se connecter strictement en utilisant le même identifiant si le justificatif n'est pas encore lié à un autre.
En d'autres termes, si je crée un compte en utilisant la connexion Google, puis (après la déconnexion) j'essaie de me connecter avec les informations d'identification Facebook en utilisant le même e-mail 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 e-mail mais des informations d'identification différentes. Connectez-vous en utilisant un fournisseur associé à cette adresse e-mail."
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 veux associer chaque utilisateur avec une information d'identification spécifique d'une manière. 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();
}
}
Veuillez vérifier le fil: https://groups.google.com/forum/#!searchin/firebase-talk/liu/firebase-talk/ms_NVQem_Cw/8g7BFk1IAAAJ Il explique pourquoi cela se produit. Cela est dû à un problème de sécurité avec les e-mails Google en cours de vérification, contrairement aux e-mails Facebook.
Autoriser la création de plusieurs comptes avec la même adresse e-mail est ce que vous recherchez.
J'ai finalement terminé avec cette logique:
Si l'utilisateur essaie de se connecter avec Facebook, mais que l'utilisateur avec l'e-mail donné existe déjà (avec le fournisseur Google) et que ces erreurs se produisent:
"Un compte existe déjà avec la même adresse e-mail mais des informations d'identification différentes. Connectez-vous en utilisant un fournisseur associé à cette adresse e-mail."
Donc, il suffit de demander à l'utilisateur de se connecter à l'aide de Google (et ensuite de lier silencieusement Facebook à un compte existant)
Pour minimiser les clics sur l'interface utilisateur de connexion sans compromettre la sécurité du compte, l'authentification Firebase a un concept de "fournisseur de confiance", où le fournisseur d'identité est également le fournisseur de services 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 e-mail", l'authentification Firebase essaie de lier le compte en fonction de l'adresse e-mail. Si un utilisateur se connecte à partir d'un fournisseur de confiance, l'utilisateur se connecte immédiatement au compte car nous savons que l'utilisateur possède l'adresse e-mail.
S'il existe un compte existant avec la même adresse e-mail mais créé avec des informations d'identification non approuvées (par exemple, fournisseur ou mot de passe non approuvé), les informations d'identification précédentes sont supprimées pour des raisons de sécurité. Un phishing (qui n'est pas le propriétaire de l'adresse e-mail) 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'e-mail dans votre backend et c'est la référence pour vos utilisateurs. Si vous utilisez l'identifiant Firebase, cela ne permettra pas de conserver des utilisateurs uniques.