Проверка / аутентификация Firebase SMS
для клиентского проекта Я создаю простой гибрид приложение, которое выполняет очень простую функцию, но будет иметь высокий трафик. Приложение обычно не нуждается в бэкэнде, так как это очень просто, и firebase кажется идеальным решением для проекта.
единственная часть, где я застрял, - это проверка / аутентификация SMS с Firebase. Тем не менее, после некоторого интенсивного гугления и чтения дока я понял, что нет простого способа сделать это. Вот что я заглянул так далеко :
- ткань.io цифры имеет отличный JS API, однако по какой-то причине firebase и цифры не будут хорошо играть вместе:https://groups.google.com/forum#!тема / firebase-talk / sB7lPuyCVBQ
- Facebook Аккаунт Kit - всего неделю назад Facebook выпустил новый комплект для проверки и аутентификации SMS, хотя он по-прежнему чувствует, что у него та же проблема, что и у fabric.IO цифры, по крайней мере, пока не доказано иначе.
- Twilio / Nexmo через NodeJS-это оба epic-сервиса с отличными API JS, однако, насколько я понимаю, для обработки обмена токенами JWT потребуется отдельный сервер. И что сам по себе еще один сервер, который станет узким местом при высоком трафике, и еще одной уязвимой точкой для безопасности, клиентской команде придется управлять отдельно. Не самый приятный.
- Twilio / Nexmo & Auth0 - пока это похоже на лучший вариант, где аутентификация и управление пользователями обрабатываются Auth0, однако это решение может быстро стоить дорого, учитывая, что twilio или nexmo и auth0 являются платными решениями. Не то чтобы я дешевка, ожидая, что все будет работать бесплатно, но чувствует себя очень дорогим дополнительным шагом, учитывая, что это просто переслать токены. [см.: клиенты-из-ада]
- Я помню, что где-то читал предложение, например, использовать номера телефонов в качестве электронных писем на firebase, например: 123-456-7890@example.com и использовать коды безопасности, отправленные по sms в качестве пароля, который звучит очень отрывочно по многим причинам.
обычно с гибридными мобильными приложениями виновата неродная природа их или API JS, но впервые (по крайней мере для меня) кажется, что это не так. Я предполагаю, что на данный момент Firebase не является допустимым вариантом, но хотел спросить любящих и заботливых членов сообщества в последний раз, прежде чем начать смотреть в AWS и настраивать весь бэкэнд для клиент.
есть ли другой способ обработки этого типа аутентификации минус средний сервис / без бэкэнд-сервера? У кого есть опыт использования этих решений?
ОБНОВЛЕНИЕ: МАЙ 2017
проверка телефона и аутентификация теперь изначально доступны в Firebase. посмотреть мои собственн-написал ответ ниже.
ОБНОВЛЕНИЕ: АПРЕЛЬ 2017
Firebase сейчас поддерживает Облачные Функции. Теперь вы можете выполнить это и многое другое с помощью облачных функций без настройки каких-либо серверов.
ОБНОВЛЕНИЕ: ОКТЯБРЬ 2017
ткань.io и Firebase сотрудничали и интегрировались цифры в аутентификации телефона Firebase и запустил больше возможностей для ткани.
4 ответов
по состоянию на 17 мая 2017, удивительные люди на Firebase испекли аутентификацию телефона цифр в Firebase. Теперь это невероятно легко достичь изначально в Firebase, более или менее с щелчком переключателя и без необходимости внешней службы или чего-либо подобного. вы можете прочитать больше об этом в docs :)
Я не могу говорить с каждой интеграцией, о которой Вы упомянули, но вы можете попробовать услуги другого Twilio, Authy.
мы недавно выпустили готовые образцы кода производства с помощью учебных пособий, чтобы помочь людям работать с такими проблемами.
один такой пример проведет вас через:
- отправка уведомления толчка OneTouch в мобильное приложение Authy или
- отправка токена через мобильное приложение Authy или
- отправка одноразовый токен в текстовом сообщении, отправленном с Authy через В Twilio.
- это 2FA с Authy учебник. следующие узлы.фрагмент JS показывает конечную точку, ожидающую утверждения или отказа статуса пользователя. Если пользователь одобрил запрос OneTouch, мы сохраним его сеанс как confirmed
, который официально регистрирует их.
Если запрос был отклонен, мы оказываем /verify
страница и попросите пользователя войти в систему с помощью маркера.
// 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 });
}
};
Итак, это действительно требует, чтобы у вас есть сервер. Но, учитывая пример, это должно помочь вам решить, что будет лучше всего работать для вашего приложения.
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;
}
}
в вашей деятельности инициализируйте авторизацию 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);
}
и, наконец, вызовите метод firebase для аутентификации
public void startAuthenticationByPhone(){
if (!validatePhoneNumber(phoneInput)) {
return;
}
startPhoneNumberVerification(phoneInput.getText().toString());
}......
теперь телефон auth доступен в firebase.Вот код для телефона Auth с помощью 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;
}
};