telefono studio signinwithphonenumber phone auth autenticacion authentication firebase twilio twitter-fabric nexmo

authentication - studio - Verificación/autenticación de SMS de Firebase



signinwithphonenumber firebase (4)

Para un proyecto de cliente, estoy creando una aplicación híbrida simple que cumple una función muy simple, pero que tendrá mucho tráfico. La aplicación normalmente no necesitaría un back-end, ya que es muy simple, y Firebase parece una solución perfecta para el proyecto.

La única parte en la que estoy atascado es la verificación / autenticación de SMS con Firebase. Sin embargo, después de una intensa búsqueda en Google y lectura en Google, me he dado cuenta de que no hay una manera fácil de hacerlo. Esto es lo que he estudiado hasta ahora:

  1. Fabric.io Digits tiene una gran API de JS, sin embargo, por alguna razón, firebase y dígitos no se jugarán bien juntos: https://groups.google.com/forum/#!topic/firebase-talk/sB7lPuyCVBQ
  2. Kit de cuenta de Facebook : hace apenas una semana, Facebook lanzó un nuevo kit de autentificación y verificación de SMS, aunque todavía parece que tiene el mismo problema que los dígitos de fabric.io, al menos hasta que se demuestre lo contrario.
  3. Twilio / Nexmo vía NodeJS - Estos son servicios épicos con excelentes API JS, sin embargo, por lo que entiendo, esto requeriría un servidor backend separado para manejar el intercambio de tokens JWT. Y eso por sí solo es otro servidor, que se convertiría en el cuello de botella durante el alto tráfico, y otro punto de vulnerabilidad para la seguridad, el equipo del cliente tendría que administrar por separado. No es el más agradable.
  4. Twilio / Nexmo y Auth0: hasta ahora, esta parece ser la mejor opción, donde Auth0 maneja la autenticación y la administración de usuarios, sin embargo, esta solución puede volverse costosa rápidamente dado que twilio o nexmo y auth0 son soluciones pagas. No es que sea un cheapo esperando que las cosas funcionen gratis, sino que se siente como un paso adicional muy costoso, dado que solo se trata de reenviar tokens. [ver: clientes-del-infierno]
  5. Recuerdo haber leído en alguna parte, una sugerencia como usar números de teléfono como correos electrónicos en firebase como: [email protected] y usar los códigos de seguridad enviados a través de sms como contraseña, que suena muy incompleto por muchas razones diferentes.

Por lo general, con las aplicaciones móviles híbridas, la naturaleza no nativa de ellas o las API JS tienen la culpa, pero por primera vez (al menos para mí) parece que este no es el caso. Supongo que en este punto Firebase no es una opción válida, pero quería preguntarle a los miembros cariñosos y afectuosos de la comunidad una última vez antes de comenzar a buscar en AWS y configurar un back-end completo para el cliente.

¿Hay alguna otra forma de manejar este tipo de autenticación menos el servicio intermedio / sin un servidor de backend? ¿Alguien tiene experiencia en el uso de estas soluciones?

ACTUALIZACIÓN: MAYO 2017

La verificación y autenticación del teléfono ahora está disponible de forma nativa en Firebase. Ver mi respuesta publicada a continuación.

ACTUALIZACIÓN: ABRIL 2017

Firebase ahora admite nativamente Cloud Functions . Ahora puede lograr esto y mucho más usando Cloud Functions sin configurar ningún servidor.


No puedo hablar de todas las integraciones que mencionaste, pero tal vez quieras probar otro de los servicios de Twilio, Authy.

Recientemente hemos lanzado ejemplos de código listos para producción a través de tutoriales para ayudar a las personas a superar este tipo de problemas.

Un ejemplo de este tipo lo guiará a través de:

  • Enviar una notificación de inserción de OneTouch a la aplicación móvil Authy o
  • Enviar un token a través de la aplicación móvil Authy o
  • Enviar un token de un solo uso en un mensaje de texto enviado con Authy a través de Twilio.

es el 2FA con el tutorial de Authy . El siguiente fragmento de Node.js muestra el punto final en espera de que se apruebe o deniegue el estado del usuario. Si el usuario ha aprobado la solicitud OneTouch, guardaremos su sesión como confirmed , que oficialmente inicia sesión.

Si se rechazó la solicitud, presentamos la página /verify y solicitamos al usuario que inicie sesión con un token.

// Internal endpoint for checking the status of OneTouch exports.authyStatus = function(request, response) { var status = (request.user) ? request.user.authyStatus : ''unverified''; if (status == ''approved'') { request.session.confirmed = true; request.session.save(function(err) { if (err) return error(response, 500, ''There was an error validating your session.''); }); } if (!request.session) { return error(response, 404, ''No valid session found for this user.''); } else { response.send({ status: status }); } };

Entonces, esto de hecho requiere que tengas un servidor. Pero dado el avance en la muestra, esto debería ayudarlo a decidir qué funcionará mejor para su aplicación.



Ahora la autenticación de teléfono está disponible en firebase. Aquí está el código para la autenticación de teléfono usando Firebase:

EditText phoneNum,Code;// two edit text one for enter phone number other for enter OTP code Button sent_,Verify;// sent button to request for verification and verify is for to verify code private PhoneAuthProvider.ForceResendingToken mResendToken; private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks; private FirebaseAuth mAuth; private String mVerificationId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_phone_number_auth); phoneNum =(EditText) findViewById(R.id.fn_num); Code =(EditText) findViewById(R.id.code); sent_ =(Button)findViewById(R.id.sent_nu); Verify =(Button)findViewById(R.id.verify); callback_verificvation(); ///function initialization mAuth = FirebaseAuth.getInstance(); sent_.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String num=phoneNum.getText().toString(); startPhoneNumberVerification(num); // call function for receive OTP 6 digit code } }); Verify.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String code=Code.getText().toString(); verifyPhoneNumberWithCode(mVerificationId,code); //call function for verify code } }); } private void startPhoneNumberVerification(String phoneNumber) { // [START start_phone_auth] PhoneAuthProvider.getInstance().verifyPhoneNumber( phoneNumber, // Phone number to verify 60, // Timeout duration TimeUnit.SECONDS, // Unit of timeout this, // Activity (for callback binding) mCallbacks); // OnVerificationStateChangedCallbacks // [END start_phone_auth] } private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) { mAuth.signInWithCredential(credential) .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { // Sign in success, update UI with the signed-in user''s information FirebaseUser user = task.getResult().getUser(); Toast.makeText(getApplicationContext(), "sign in successfull", Toast.LENGTH_SHORT).show(); } else { // Sign in failed, display a message and update the UI if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) { // The verification code entered was invalid } } } }); } private void verifyPhoneNumberWithCode(String verificationId, String code) { // [START verify_with_code] PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code); // [END verify_with_code] signInWithPhoneAuthCredential(credential); } private void callback_verificvation() { mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { @Override public void onVerificationCompleted(PhoneAuthCredential credential) { // This callback will be invoked in two situations: // 1 - Instant verification. In some cases the phone number can be instantly // verified without needing to send or enter a verification code. // 2 - Auto-retrieval. On some devices Google Play services can automatically // detect the incoming verification SMS and perform verificaiton without // user action. signInWithPhoneAuthCredential(credential); } @Override public void onVerificationFailed(FirebaseException e) { // This callback is invoked in an invalid request for verification is made, // for instance if the the phone number format is not valid. if (e instanceof FirebaseAuthInvalidCredentialsException) { // Invalid request } else if (e instanceof FirebaseTooManyRequestsException) { // The SMS quota for the project has been exceeded } // Show a message and update the UI } @Override public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) { // The SMS verification code has been sent to the provided phone number, we // now need to ask the user to enter the code and then construct a credential // by combining the code with a verification ID. // Save verification ID and resending token so we can use them later mVerificationId = verificationId; mResendToken = token; } };


import android.app.Activity; import android.os.Bundle; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.widget.EditText; import android.widget.Toast; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.FirebaseException; import com.google.firebase.FirebaseTooManyRequestsException; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.PhoneAuthCredential; import com.google.firebase.auth.PhoneAuthProvider; import java.util.concurrent.TimeUnit; public class PhoneAutenticationService { public PhoneAutenticationService(Activity activity,FirebaseAuth auth) { this.activity = activity; this.mAuth = auth; setupCallback(); } private static final String TAG = PhoneAutenticationService.class.getSimpleName(); private Activity activity; private String verificationCode; private static final String KEY_VERIFY_IN_PROGRESS = "key_verify_in_progress"; private static final int STATE_INITIALIZED = 1; private static final int STATE_CODE_SENT = 2; private static final int STATE_VERIFY_FAILED = 3; private static final int STATE_VERIFY_SUCCESS = 4; private static final int STATE_SIGNIN_FAILED = 5; private static final int STATE_SIGNIN_SUCCESS = 6; // [START declare_auth] private FirebaseAuth mAuth; // [END declare_auth] private boolean mVerificationInProgress = false; private String mVerificationId; private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks; private PhoneAuthProvider.ForceResendingToken mResendToken; protected void onSaveInstanceState(Bundle outState) { outState.putBoolean(KEY_VERIFY_IN_PROGRESS, mVerificationInProgress); } protected void onRestoreInstanceState(Bundle savedInstanceState) { mVerificationInProgress = savedInstanceState.getBoolean(KEY_VERIFY_IN_PROGRESS); } // [START on_start_check_user] public void onStart(EditText mPhoneNumberField) { // Check if user is signed in (non-null) and update UI accordingly. FirebaseUser currentUser = mAuth.getCurrentUser(); updateUI(currentUser); // [START_EXCLUDE] if (mVerificationInProgress && validatePhoneNumber(mPhoneNumberField)) { startPhoneNumberVerification(mPhoneNumberField.getText().toString()); } // [END_EXCLUDE] } // [END on_start_check_user] private void setupCallback(){ mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { @Override public void onVerificationCompleted(PhoneAuthCredential credential) { // This callback will be invoked in two situations: // 1 - Instant verification. In some cases the phone number can be instantly // verified without needing to send or enter a verification code. // 2 - Auto-retrieval. On some devices Google Play services can automatically // detect the incoming verification SMS and perform verificaiton without // user action. Log.d(TAG, "onVerificationCompleted:" + credential); // [START_EXCLUDE silent] mVerificationInProgress = false; // [END_EXCLUDE] // [START_EXCLUDE silent] // Update the UI and attempt sign in with the phone credential updateUI(STATE_VERIFY_SUCCESS, credential); // [END_EXCLUDE] signInWithPhoneAuthCredential(credential); } @Override public void onVerificationFailed(FirebaseException e) { // This callback is invoked in an invalid request for verification is made, // for instance if the the phone number format is not valid. Log.w(TAG, "onVerificationFailed", e); // [START_EXCLUDE silent] mVerificationInProgress = false; // [END_EXCLUDE] if (e instanceof FirebaseAuthInvalidCredentialsException) { // Invalid request // [START_EXCLUDE] Toast.makeText(activity,"Invalid phone number.",Toast.LENGTH_SHORT).show(); // [END_EXCLUDE] } else if (e instanceof FirebaseTooManyRequestsException) { // The SMS quota for the project has been exceeded // [START_EXCLUDE] Toast.makeText(activity,"Quota exceeded.",Toast.LENGTH_SHORT).show(); // [END_EXCLUDE] } // Show a message and update the UI // [START_EXCLUDE] updateUI(STATE_VERIFY_FAILED); // [END_EXCLUDE] } @Override public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) { // The SMS verification code has been sent to the provided phone number, we // now need to ask the user to enter the code and then construct a credential // by combining the code with a verification ID. Log.d(TAG, "onCodeSent:" + verificationId); Toast.makeText(activity,"onCodeSent:" + verificationId,Toast.LENGTH_SHORT).show(); verificationCode = verificationId; // Save verification ID and resending token so we can use them later mVerificationId = verificationId; setVerificationCode(verificationId); mResendToken = token; // [START_EXCLUDE] // Update UI updateUI(STATE_CODE_SENT); // [END_EXCLUDE] } }; } public void startPhoneNumberVerification(String phoneNumber) { // [START start_phone_auth] PhoneAuthProvider.getInstance().verifyPhoneNumber( phoneNumber, // Phone number to verify 60, // Timeout duration TimeUnit.SECONDS, // Unit of timeout activity, // Activity (for callback binding) mCallbacks); // OnVerificationStateChangedCallbacks // [END start_phone_auth] mVerificationInProgress = true; } public void verifyPhoneNumberWithCode(String verificationId, String code) { // [START verify_with_code] PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code); // [END verify_with_code] signInWithPhoneAuthCredential(credential); } // [START resend_verification] public void resendVerificationCode(String phoneNumber, PhoneAuthProvider.ForceResendingToken token) { PhoneAuthProvider.getInstance().verifyPhoneNumber( phoneNumber, // Phone number to verify 60, // Timeout duration TimeUnit.SECONDS, // Unit of timeout activity, // Activity (for callback binding) mCallbacks); // resending // [END start_phone_auth] } // [END resend_verification] // [START sign_in_with_phone] public void signInWithPhoneAuthCredential(PhoneAuthCredential credential) { mAuth.signInWithCredential(credential) .addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { // Sign in success, update UI with the signed-in user''s information Log.d(TAG, "signInWithCredential:success"); Toast.makeText(activity,"signInWithCredential:success",Toast.LENGTH_SHORT).show(); FirebaseUser user = task.getResult().getUser(); // [START_EXCLUDE] updateUI(STATE_SIGNIN_SUCCESS, user); // [END_EXCLUDE] } else { // Sign in failed, display a message and update the UI Log.w(TAG, "signInWithCredential:failure", task.getException()); if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) { // The verification code entered was invalid // [START_EXCLUDE silent] Toast.makeText(activity,"Invalid code.",Toast.LENGTH_SHORT).show(); // [END_EXCLUDE] } // [START_EXCLUDE silent] // Update UI updateUI(STATE_SIGNIN_FAILED); // [END_EXCLUDE] } } }); } // [END sign_in_with_phone] public void signOut() { mAuth.signOut(); updateUI(STATE_INITIALIZED); } private void updateUI(int uiState) { updateUI(uiState, mAuth.getCurrentUser(), null); } public void updateUI(FirebaseUser user) { if (user != null) { updateUI(STATE_SIGNIN_SUCCESS, user); } else { updateUI(STATE_INITIALIZED); } } private void updateUI(int uiState, FirebaseUser user) { updateUI(uiState, user, null); } private void updateUI(int uiState, PhoneAuthCredential cred) { updateUI(uiState, null, cred); } private void updateUI(int uiState, FirebaseUser user, PhoneAuthCredential cred) { switch (uiState) { case STATE_INITIALIZED: // Initialized state, show only the phone number field and start button Toast.makeText(activity,"Initialized state",Toast.LENGTH_SHORT).show(); break; case STATE_CODE_SENT: // Code sent state, show the verification field, the Toast.makeText(activity,"Code sent state",Toast.LENGTH_SHORT).show(); break; case STATE_VERIFY_FAILED: // Verification has failed, show all options Toast.makeText(activity,"Verification has failed",Toast.LENGTH_SHORT).show(); break; case STATE_VERIFY_SUCCESS: // Verification has succeeded, proceed to firebase sign in Toast.makeText(activity,"Verification has succeeded",Toast.LENGTH_SHORT).show(); // Set the verification text based on the credential if (cred != null) { if (cred.getSmsCode() != null) { //mVerificationField.setText(cred.getSmsCode()); } else { Toast.makeText(activity,"Invalid verification code.",Toast.LENGTH_SHORT).show(); } } break; case STATE_SIGNIN_FAILED: // No-op, handled by sign-in check Toast.makeText(activity,"Sign in failed",Toast.LENGTH_SHORT).show(); break; case STATE_SIGNIN_SUCCESS: // Np-op, handled by sign-in check Toast.makeText(activity,"Sign in sucesssss!!!!",Toast.LENGTH_SHORT).show(); break; } if (user == null) { // Signed out } else { // Signed in } } public boolean validatePhoneNumber(EditText mPhoneNumberField) { String phoneNumber = mPhoneNumberField.getText().toString(); if (TextUtils.isEmpty(phoneNumber) || phoneNumber.length()>10 || phoneNumber.length()<9) { Toast.makeText(activity,"Invalid phone number.",Toast.LENGTH_SHORT).show(); return false; } return true; } public PhoneAuthProvider.OnVerificationStateChangedCallbacks getmCallbacks() { return mCallbacks; } public PhoneAuthProvider.ForceResendingToken getmResendToken() { return mResendToken; } public FirebaseAuth getmAuth() { return mAuth; } public String getVerificationCode() { return verificationCode; } public void setVerificationCode(String verificationCode) { this.verificationCode = verificationCode; }

}

En tu actividad, inicia la autenticación y el escucha de Firebase

mAuth = FirebaseAuth.getInstance(); mAuthListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { FirebaseUser user = firebaseAuth.getCurrentUser(); if (user != null) { Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); } else { Log.d(TAG, "onAuthStateChanged:signed_out"); } // ... } }; //init all auth process phoneAutenticationService = new PhoneAutenticationService(this,mAuth); @Override public void onStart() { super.onStart(); mAuth.addAuthStateListener(mAuthListener); getActivity().registerReceiver(smsBroadcastReceiver, filter);// define e broadcast receiver to intercept a sms verification code } @Override public void onStop() { super.onStop(); if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener);sms code } getActivity().unregisterReceiver(smsBroadcastReceiver); }

y finalmente llame al método firebase para autenticación

public void startAuthenticationByPhone(){ if (!validatePhoneNumber(phoneInput)) { return; } startPhoneNumberVerification(phoneInput.getText().toString()); }......