android - sesion - firebase login example
La autenticación usando Facebook al principio y luego Google causa un error en Firebase para Android (6)
Según tengo entendido por Firebase Docs , si un usuario autentica su cuenta con una credencial, debe iniciar sesión estrictamente usando la misma credencial si la credencial aún no está vinculada con otra.
En otras palabras, si creo una cuenta usando el inicio de sesión de Google y luego (después de cerrar sesión) intento iniciar sesión con la credencial de Facebook usando el mismo correo electrónico que se usa para la credencial de Google, debería ver esta excepción en logcat:
"Ya existe una cuenta con la misma dirección de correo electrónico pero con credenciales de inicio de sesión diferentes. Inicie sesión con un proveedor asociado con esta dirección de correo electrónico".
Y sí, me sorprende esta excepción. Pero si creo una cuenta usando Facebook y luego intento iniciar sesión con la credencial de Google, el proveedor de esta cuenta (Facebook) se convierte a Google. Esta vez, la autenticación no falla pero no es el resultado esperado. Quiero asociar a cada usuario con una credencial específica de alguna manera. ¿Cómo debo arreglar esto? Puedes ver el código a continuación:
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();
}
}
Para minimizar los clics de la interfaz de usuario de inicio de sesión sin comprometer la seguridad de la cuenta, Firebase Authentication tiene un concepto de ''proveedor de confianza'', donde el proveedor de identidad también es el proveedor de servicios de correo electrónico. Por ejemplo, Google es el proveedor confiable para las direcciones @ gmail.com, Yahoo es el proveedor confiable para las direcciones @ yahoo.com y Microsoft para las direcciones @ outlook.com.
En el modo "Una cuenta por dirección de correo electrónico", Firebase Authentication intenta vincular la cuenta en función de la dirección de correo electrónico. Si un usuario inicia sesión desde un proveedor de confianza, el usuario inicia sesión inmediatamente en la cuenta ya que sabemos que el usuario posee la dirección de correo electrónico.
Si hay una cuenta existente con la misma dirección de correo electrónico pero creada con credenciales no confiables (por ejemplo, proveedor o contraseña no confiables), las credenciales anteriores se eliminan por razones de seguridad. Un phisher (que no es el propietario de la dirección de correo electrónico) podría crear la cuenta inicial; eliminar la credencial inicial evitaría que el phisher acceda a la cuenta posteriormente.
Jin Liu
Consulte el hilo: https://groups.google.com/forum/#!searchin/firebase-talk/liu/firebase-talk/ms_NVQem_Cw/8g7BFk1IAAAJ Explica por qué sucede esto. Esto se debe a algún problema de seguridad con los correos electrónicos de Google que se verifican, mientras que los correos electrónicos de Facebook no.
Finalmente terminé con esta lógica:
Si el usuario intenta iniciar sesión con Facebook, pero el usuario con un correo electrónico dado ya existe (con el proveedor de Google) y se produce este error:
"Ya existe una cuenta con la misma dirección de correo electrónico pero con credenciales de inicio de sesión diferentes. Inicie sesión con un proveedor asociado con esta dirección de correo electrónico".
Por lo tanto, solo pídale al usuario que inicie sesión con Google (y luego enlace silenciosamente Facebook a la cuenta existente)
Permitir la creación de varias cuentas con la misma dirección de correo electrónico es lo que está buscando.
Eso funciona bien SOLO si revisas el correo electrónico en tu backend y esa es la referencia para tus usuarios. Si usa el ID de Firebase, eso no permitirá mantener usuarios únicos.
Permitir la creación de varias cuentas con la misma dirección de correo electrónico es lo que está buscando.
Tuve el mismo problema, todo lo que tienes que hacer es ir a Firebase Console y luego, en la categoría "Autenticación", eliminar el usuario que deseas.
Eso me funciona.