17

Wie ich aus der Firebase Docs verstehe, wenn ein Benutzer seinen Account mit einem Berechtigungsnachweis authentifiziert, sollte er sich streng mit denselben Anmeldeinformationen anmelden, wenn der Berechtigungsnachweis nicht verknüpft ist mit noch einem anderen. Wenn ich mit Google ein Konto erstelle und dann (nach dem Abmelden) versuche, mich mit den Facebook-Anmeldeinformationen mit der gleichen E-Mail-Adresse wie für die Google-Anmeldeinformationen anzumelden, sollte diese Ausnahme in der E-Mail-Adresse angezeigt werden logcat:Authentifizierung mit Facebook zuerst und dann Google verursacht einen Fehler in Firebase für Android

„ein Konto existiert bereits mit der gleichen E-Mail-Adresse, aber unterschiedlichen Anmeldeinformationen Anmeldung eines Provider mit dieser E-Mail-Adresse zugeordnet ist..“

Und ja, ich bekomme diese Ausnahme nicht überraschend. Wenn ich jedoch ein Konto über Facebook erstelle und anschließend versuche, mich mit den Google-Anmeldedaten anzumelden, wird der Anbieter dieses Kontos (Facebook) in Google umgewandelt. Diesmal schlägt die Authentifizierung nicht fehl, aber es ist nicht das erwartete Ergebnis. Ich möchte jedem Benutzer auf bestimmte Weise einen bestimmten Berechtigungsnachweis zuordnen. Wie soll ich das beheben? Sie können den Code unten:

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

ich die gleiche Sache zu bekommen, Sie irgendeine Abhilfe gefunden? – r3dm4n

+1

Siehe Bojeils Antwort bitte. –

+0

Yup, überprüfte das, aber ich dachte, es könnte ein Workaround sein. Wenn Sie beispielsweise zulassen - mehrere Konten pro E-Mail-Adresse - erhalten Sie diese nicht mehr, aber Benutzer sind nicht in der Datenbank verknüpft. – r3dm4n

Antwort

8

Bitte überprüfen Sie den Faden: https://groups.google.com/forum/#!searchin/firebase-talk/liu/firebase-talk/ms_NVQem_Cw/8g7BFk1IAAAJ Es erklärt, warum dies geschieht. Dies ist auf ein Sicherheitsproblem zurückzuführen, bei dem Google-E-Mails verifiziert werden, während dies bei Facebook-E-Mails nicht der Fall ist.

+8

Das riecht wirklich. Google wandelt automatisch Konten automatisch in Google-Konten um, tut dies jedoch nicht bei Facebook und gibt stattdessen einen Fehler aus. Dieser "Trusted Provider" Quatsch ist eine Ausrede. Kein Benutzer würde erwarten, dass sein E-Mail-/Passwort-Konto stillschweigend gesperrt wurde. Ich möchte, dass sie konsistent sind. Google sollte keine Konten stillschweigend konvertieren. Wie kann ich dieses Verhalten verhindern, wenn ich im Modus "Ein Konto pro E-Mail" bin? –

4

Um die Anmelde-UI-Klicks zu minimieren, ohne die Kontosicherheit zu beeinträchtigen, hat Firebase Authentication das Konzept des "vertrauenswürdigen Anbieters", wobei der Identity-Provider auch der E-Mail-Dienstanbieter ist. Beispielsweise ist Google der vertrauenswürdige Anbieter für @ gmail.com-Adressen, Yahoo ist der vertrauenswürdige Anbieter für @ yahoo.com-Adressen und Microsoft für @ outlook.com-Adressen.

Im Modus "Ein Konto pro E-Mail-Adresse" versucht die Firebase-Authentifizierung, das Konto basierend auf der E-Mail-Adresse zu verknüpfen. Wenn sich ein Benutzer bei einem vertrauenswürdigen Anbieter anmeldet, meldet er sich sofort beim Konto an, da wir wissen, dass der Benutzer die E-Mail-Adresse besitzt.

Wenn ein Konto mit derselben E-Mail-Adresse existiert, aber mit nicht vertrauenswürdigen Anmeldeinformationen (z. B. nicht vertrauenswürdiger Anbieter oder Kennwort) erstellt wurde, werden die vorherigen Anmeldeinformationen aus Sicherheitsgründen entfernt. Ein Phisher (der nicht der Besitzer der E-Mail-Adresse ist) erstellt möglicherweise das ursprüngliche Konto. Wenn die anfängliche Berechtigung entfernt wird, kann der Phisher nicht mehr auf das Konto zugreifen.

Jin Liu

4

ich endlich mit dieser Logik beendet:

Wenn Benutzer mit Facebook anmelden versuchen, aber Benutzer mit bestimmten E-Mail gibt es bereits (mit Google-Provider) und der Fehler tritt auf:

"Ein Konto existiert bereits mit der gleichen E-Mail-Adresse, aber andere Anmelde Crede ntials. Melden Sie sich mit einem Anbieter an, der dieser E-Mail-Adresse zugeordnet ist."

Also, fragen Sie einfach Benutzer loging mit Google (und nachdem es still Facebook zu bestehenden Konto verknüpfen)

Facebook and Google Sign In logics using firebase

-3

ich hatte das gleiche Problem, alles, was Sie tun müssen, ist gehen zu Firebase Console und dann in der „Authentifizierung“ Kategorie löschen Sie den Benutzer, die Sie möchten.

das ist für mich funktioniert.