17

Come ho capito dallo Firebase Docs, se un utente autentica il proprio account con una credenziale, deve effettuare il login rigorosamente utilizzando la stessa credenziale se la credenziale non è collegata con un altro ancora.L'autenticazione con Facebook all'inizio e poi Google causa un errore in Firebase per Android

In altre parole, se creo un account utilizzando Google accedi e poi (dopo la disconnessione) prova ad accedere con le credenziali di Facebook utilizzando la stessa email utilizzata per le credenziali di Google, dovrei vedere questa eccezione logcat:

"esiste già un account con lo stesso indirizzo e-mail, ma diverse le credenziali di accesso Accedi utilizzando un provider associato a questo indirizzo email .".

E sì, ho questa eccezione non sorprende. Ma se creo un account utilizzando Facebook, e poi provo ad accedere con le credenziali di Google, il fornitore di questo account (Facebook) viene convertito in Google. Questa volta l'autenticazione non fallisce ma non è il risultato atteso. Voglio associare ciascun utente con una credenziale specifica in un modo. Come dovrei risolvere questo? Si può vedere il codice qui sotto:

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(); 
    } 
} 
+1

ottengo la stessa cosa, ha trovato alcuna soluzione? – r3dm4n

+1

Guarda la risposta di bojeil per favore. –

+0

Sì, l'ho verificato, ma ho pensato che potesse esserci una soluzione alternativa. Ad esempio, se consenti - più account per indirizzo e-mail - questo non lo si ottiene più, ma gli utenti non sono collegati nel database. – r3dm4n

risposta

8

Si prega di controllare il filo: https://groups.google.com/forum/#!searchin/firebase-talk/liu/firebase-talk/ms_NVQem_Cw/8g7BFk1IAAAJ Spiega perché questo accade. Ciò è dovuto a un problema di sicurezza con la verifica delle e-mail di Google mentre le e-mail di Facebook non lo sono.

+8

Questo davvero odora. Google converte automaticamente gli account in account Google, ma non fa lo stesso per Facebook e invece restituisce un errore. Questa assurdità del "fornitore di fiducia" è una scusa. Nessun utente si aspetterebbe che il suo account email/password sia stato revocato automaticamente. Voglio che siano coerenti. Google non dovrebbe convertire automaticamente gli account. Come posso evitare questo comportamento quando sono in modalità "un account per email"? –

4

Per ridurre al minimo i clic dell'interfaccia utente di accesso senza compromettere la sicurezza dell'account, Firebase Authentication ha un concetto di 'provider di fiducia', in cui il provider di identità è anche il provider di servizi di posta elettronica. Ad esempio, Google è il provider affidabile per gli indirizzi di @ gmail.com, Yahoo è il provider affidabile per gli indirizzi @ yahoo.com e Microsoft per gli indirizzi @ outlook.com.

Nella modalità "Un account per indirizzo di posta elettronica", Firebase Authentication tenta di collegare l'account in base all'indirizzo e-mail. Se un utente accede dal provider di fiducia, l'utente accede immediatamente all'account poiché sappiamo che l'utente possiede l'indirizzo email.

Se esiste un account esistente con lo stesso indirizzo email ma creato con credenziali non attendibili (ad esempio provider o password non attendibili), le credenziali precedenti vengono rimosse per motivi di sicurezza. Un phisher (che non è il proprietario dell'indirizzo email) potrebbe creare l'account iniziale: rimuovere la credenziale iniziale impedirebbe al phisher di accedere successivamente all'account.

Jin Liu

4

fine ho finito con questa logica:

Se l'utente tenta di accedere a Facebook, ma l'utente con e-mail fornito già presente (con il fornitore Google) e questo errori occures:

"esiste già un account con lo stesso indirizzo e-mail, ma diversi Crede di accesso ntials. Accedi utilizzando un provider associato a questo indirizzo email ."

Quindi, basta chiedere all'utente di loging utilizzando Google (e dopo in silenzio collegare Facebook a account esistente)

Facebook and Google Sign In logics using firebase

-3

Ho avuto lo stesso problema, tutto quello che dovete fare è andare a Firebase Console e poi nella categoria "autenticazione" cancellare l'utente che si desidera.

che lavora per me.