Se você fez upgrade para o Firebase Authentication with Identity Platform, pode adicionar a autenticação multifator por SMS ao app Android.
A autenticação multifator aumenta a segurança do app. Os invasores costumam comprometer as senhas e contas de redes sociais, mas é mais difícil interceptar uma mensagem de texto.
Antes de começar
Ative pelo menos um provedor compatível com a autenticação multifator. Todos os provedores são compatíveis com a autenticação multifator (MFA), exceto as autenticações por smartphone e a anônima e o Apple Game Center.
Confirme se o app está verificando os e-mails do usuário. A autenticação multifator (MFA) requer verificação de e-mail. Isso impede que agentes mal-intencionados se registrem em um serviço com um e-mail que não tenham e bloqueiem o proprietário real adicionando um segundo fator.
Registre o hash SHA-1 do seu app no Console do Firebase. As alterações serão transferidas automaticamente para Google Cloud Firebase.
Siga as etapas em Como autenticar seu cliente para receber o hash SHA-1 do seu app.
Abra o Console do Firebase.
Navegue até Configurações do projeto.
Em Seus apps, clique no ícone do Android.
Siga as etapas guiadas para adicionar seu hash SHA-1.
Como ativar a autenticação multifator
Abra a página Autenticação > Método de login do console do Firebase.
Na seção Avançado, ative Autenticação multifator por SMS.
Insira também os números de telefone usados para testar o app. Embora opcional, é recomendável registrar números de telefone de teste para evitar a limitação durante o desenvolvimento.
Se você ainda não autorizou o domínio do app, adicione-o à lista de permissões na página Autenticação > Configurações do console do Firebase.
Como escolher um padrão de registro
É possível escolher se o app requer autenticação multifator e como e quando registrar os usuários. Alguns padrões comuns incluem:
Registrar o segundo fator do usuário como parte do processo. Use esse método se o app exigir autenticação multifator para todos os usuários.
Oferecer uma opção pulável para registrar um segundo fator durante o processo. Os apps que quiserem incentivar, mas não exigirem, a autenticação multifator podem ter essa abordagem.
Permitir a adição de um segundo fator na página de gerenciamento da conta ou no perfil do usuário, em vez da tela de inscrição. Isso minimiza o atrito durante o processo de registro, ao mesmo tempo que disponibiliza a autenticação multifator para usuários que se preocupam com a segurança.
Exigir a adição de um segundo fator de maneira incremental quando o usuário quiser acessar recursos com requisitos de segurança aprimorados.
Como registrar um segundo fator
Para registrar um novo fator secundário para um usuário:
Reautentique o usuário.
Peça ao usuário para inserir o número de telefone.
Disponibilize uma sessão de vários fatores para o usuário:
Kotlin
user.multiFactor.session.addOnCompleteListener { task -> if (task.isSuccessful) { val multiFactorSession: MultiFactorSession? = task.result } }
Java
user.getMultiFactor().getSession() .addOnCompleteListener( new OnCompleteListener<MultiFactorSession>() { @Override public void onComplete(@NonNull Task<MultiFactorSession> task) { if (task.isSuccessful()) { MultiFactorSession multiFactorSession = task.getResult(); } } });
Crie um objeto
OnVerificationStateChangedCallbacks
para lidar com eventos diferentes no processo de verificação:Kotlin
val callbacks = object : OnVerificationStateChangedCallbacks() { override fun onVerificationCompleted(credential: PhoneAuthCredential) { // 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. You can disable this feature by calling // PhoneAuthOptions.builder#requireSmsValidation(true) when building // the options to pass to PhoneAuthProvider#verifyPhoneNumber(). // 2) Auto-retrieval. On some devices, Google Play services can // automatically detect the incoming verification SMS and perform // verification without user action. this@MainActivity.credential = credential } override fun onVerificationFailed(e: FirebaseException) { // This callback is invoked in response to invalid requests for // verification, like an incorrect phone number. if (e is FirebaseAuthInvalidCredentialsException) { // Invalid request // ... } else if (e is FirebaseTooManyRequestsException) { // The SMS quota for the project has been exceeded // ... } // Show a message and update the UI // ... } override fun onCodeSent( verificationId: String, forceResendingToken: ForceResendingToken ) { // 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 the verification ID and resending token for later use. this@MainActivity.verificationId = verificationId this@MainActivity.forceResendingToken = forceResendingToken // ... } }
Java
OnVerificationStateChangedCallbacks callbacks = new 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. You can disable this feature by calling // PhoneAuthOptions.builder#requireSmsValidation(true) when building // the options to pass to PhoneAuthProvider#verifyPhoneNumber(). // 2) Auto-retrieval. On some devices, Google Play services can // automatically detect the incoming verification SMS and perform // verification without user action. this.credential = credential; } @Override public void onVerificationFailed(FirebaseException e) { // This callback is invoked in response to invalid requests for // verification, like an incorrect phone number. 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 the verification ID and resending token for later use. this.verificationId = verificationId; this.forceResendingToken = token; // ... } };
Inicialize um objeto
PhoneInfoOptions
com o número de telefone do usuário, a sessão de vários fatores e seus callbacks:Kotlin
val phoneAuthOptions = PhoneAuthOptions.newBuilder() .setPhoneNumber(phoneNumber) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(MultiFactorSession) .setCallbacks(callbacks) .build()
Java
PhoneAuthOptions phoneAuthOptions = PhoneAuthOptions.newBuilder() .setPhoneNumber(phoneNumber) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(multiFactorSession) .setCallbacks(callbacks) .build();
Por padrão, a verificação instantânea está ativada. Para desativá-lo, adicione uma chamada a
requireSmsValidation(true)
.Envie um código de verificação ao smartphone do usuário:
Kotlin
PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions)
Java
PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions);
Não é obrigatório, mas recomendamos informar aos usuários antecipadamente que eles receberão uma mensagem SMS e quais taxas padrão serão aplicadas.
Após o envio do código SMS, peça ao usuário para fazer a verificação dele:
Kotlin
// Ask user for the verification code. val credential = PhoneAuthProvider.getCredential(verificationId, verificationCode)
Java
// Ask user for the verification code. PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, verificationCode);
Inicialize um objeto
MultiFactorAssertion
com oPhoneAuthCredential
:Kotlin
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)
Java
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
Conclua o registro. Se quiser, especifique um nome de exibição para o segundo fator. Isso é útil para usuários com vários fatores, já que o número de telefone é mascarado durante o fluxo de autenticação (por exemplo, +1******1234).
Kotlin
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. FirebaseAuth.getInstance() .currentUser ?.multiFactor ?.enroll(multiFactorAssertion, "My personal phone number") ?.addOnCompleteListener { // ... }
Java
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. FirebaseAuth.getInstance() .getCurrentUser() .getMultiFactor() .enroll(multiFactorAssertion, "My personal phone number") .addOnCompleteListener( new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // ... } });
O código abaixo mostra um exemplo completo de registro de um segundo fator:
Kotlin
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)
user.multiFactor.session
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val multiFactorSession = task.result
val phoneAuthOptions = PhoneAuthOptions.newBuilder()
.setPhoneNumber(phoneNumber)
.setTimeout(30L, TimeUnit.SECONDS)
.setMultiFactorSession(multiFactorSession)
.setCallbacks(callbacks)
.build()
// Send SMS verification code.
PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions)
}
}
// Ask user for the verification code.
val credential = PhoneAuthProvider.getCredential(verificationId, verificationCode)
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)
// Complete enrollment.
FirebaseAuth.getInstance()
.currentUser
?.multiFactor
?.enroll(multiFactorAssertion, "My personal phone number")
?.addOnCompleteListener {
// ...
}
Java
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
user.getMultiFactor().getSession()
.addOnCompleteListener(
new OnCompleteListener<MultiFactorSession>() {
@Override
public void onComplete(@NonNull Task<MultiFactorSession> task) {
if (task.isSuccessful()) {
MultiFactorSession multiFactorSession = task.getResult();
PhoneAuthOptions phoneAuthOptions =
PhoneAuthOptions.newBuilder()
.setPhoneNumber(phoneNumber)
.setTimeout(30L, TimeUnit.SECONDS)
.setMultiFactorSession(multiFactorSession)
.setCallbacks(callbacks)
.build();
// Send SMS verification code.
PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions);
}
}
});
// Ask user for the verification code.
PhoneAuthCredential credential =
PhoneAuthProvider.getCredential(verificationId, verificationCode);
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
// Complete enrollment.
FirebaseAuth.getInstance()
.getCurrentUser()
.getMultiFactor()
.enroll(multiFactorAssertion, "My personal phone number")
.addOnCompleteListener(
new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// ...
}
});
Parabéns! Você registrou um segundo fator de autenticação para um usuário.
Como fazer login dos usuários com um segundo fator
Para fazer login de um usuário com verificação por SMS de dois fatores:
Faça login do usuário com o primeiro fator e, em seguida, capture a exceção
FirebaseAuthMultiFactorException
. Esse erro contém um resolvedor, que pode ser usado para conseguir o segundo fator registrado do usuário. Ele também contém uma sessão que prova a autenticação do usuário com o primeiro fator.Por exemplo, se o primeiro fator do usuário for um e-mail e uma senha:
Kotlin
FirebaseAuth.getInstance() .signInWithEmailAndPassword(email, password) .addOnCompleteListener( OnCompleteListener { task -> if (task.isSuccessful) { // User is not enrolled with a second factor and is successfully // signed in. // ... return@OnCompleteListener } if (task.exception is FirebaseAuthMultiFactorException) { // The user is a multi-factor user. Second factor challenge is // required. val multiFactorResolver = (task.exception as FirebaseAuthMultiFactorException).resolver // ... } else { // Handle other errors, such as wrong password. } })
Java
FirebaseAuth.getInstance() .signInWithEmailAndPassword(email, password) .addOnCompleteListener( new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { // User is not enrolled with a second factor and is successfully // signed in. // ... return; } if (task.getException() instanceof FirebaseAuthMultiFactorException) { // The user is a multi-factor user. Second factor challenge is // required. MultiFactorResolver multiFactorResolver = task.getException().getResolver(); // ... } else { // Handle other errors such as wrong password. } } });
Se o primeiro fator do usuário for um provedor federado, como o OAuth, capture o erro depois de chamar
startActivityForSignInWithProvider()
.Se o usuário tiver vários fatores secundários registrados, pergunte a ele qual usar:
Kotlin
// Ask user which second factor to use. // You can get the list of enrolled second factors using // multiFactorResolver.hints // Check the selected factor: if (multiFactorResolver.hints[selectedIndex].factorId === PhoneMultiFactorGenerator.FACTOR_ID ) { // User selected a phone second factor. val selectedHint = multiFactorResolver.hints[selectedIndex] as PhoneMultiFactorInfo } else if (multiFactorResolver.hints[selectedIndex].factorId === TotpMultiFactorGenerator.FACTOR_ID) { // User selected a TOTP second factor. } else { // Unsupported second factor. }
Java
// Ask user which second factor to use. // You can get the masked phone number using // resolver.getHints().get(selectedIndex).getPhoneNumber() // You can get the display name using // resolver.getHints().get(selectedIndex).getDisplayName() if ( resolver.getHints() .get(selectedIndex) .getFactorId() .equals( PhoneMultiFactorGenerator.FACTOR_ID ) ) { // User selected a phone second factor. MultiFactorInfo selectedHint = multiFactorResolver.getHints().get(selectedIndex); } else if ( resolver .getHints() .get(selectedIndex) .getFactorId() .equals(TotpMultiFactorGenerator.FACTOR_ID ) ) { // User selected a TOTP second factor. } else { // Unsupported second factor. }
Inicialize um objeto
PhoneAuthOptions
com a dica e a sessão de vários fatores. Esses valores estão contidos no resolvedor anexado aoFirebaseAuthMultiFactorException
.Kotlin
val phoneAuthOptions = PhoneAuthOptions.newBuilder() .setMultiFactorHint(selectedHint) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(multiFactorResolver.session) .setCallbacks(callbacks) // Optionally disable instant verification. // .requireSmsValidation(true) .build()
Java
PhoneAuthOptions phoneAuthOptions = PhoneAuthOptions.newBuilder() .setMultiFactorHint(selectedHint) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(multiFactorResolver.getSession()) .setCallbacks(callbacks) // Optionally disable instant verification. // .requireSmsValidation(true) .build();
Envie um código de verificação ao smartphone do usuário:
Kotlin
// Send SMS verification code PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions)
Java
// Send SMS verification code PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions);
Após o envio do código SMS, peça ao usuário para fazer a verificação dele:
Kotlin
// Ask user for the verification code. Then, pass it to getCredential: val credential = PhoneAuthProvider.getCredential(verificationId, verificationCode)
Java
// Ask user for the verification code. Then, pass it to getCredential: PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, verificationCode);
Inicialize um objeto
MultiFactorAssertion
com oPhoneAuthCredential
:Kotlin
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)
Java
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
Chame
resolver.resolveSignIn()
para concluir a autenticação secundária. Em seguida, você pode acessar o resultado do login original, que inclui os dados padrão do provedor e as credenciais de autenticação:Kotlin
multiFactorResolver .resolveSignIn(multiFactorAssertion) .addOnCompleteListener { task -> if (task.isSuccessful) { val authResult = task.result // AuthResult will also contain the user, additionalUserInfo, // and an optional credential (null for email/password) // associated with the first factor sign-in. // For example, if the user signed in with Google as a first // factor, authResult.getAdditionalUserInfo() will contain data // related to Google provider that the user signed in with; // authResult.getCredential() will contain the Google OAuth // credential; // authResult.getCredential().getAccessToken() will contain the // Google OAuth access token; // authResult.getCredential().getIdToken() contains the Google // OAuth ID token. } }
Java
multiFactorResolver .resolveSignIn(multiFactorAssertion) .addOnCompleteListener( new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { AuthResult authResult = task.getResult(); // AuthResult will also contain the user, additionalUserInfo, // and an optional credential (null for email/password) // associated with the first factor sign-in. // For example, if the user signed in with Google as a first // factor, authResult.getAdditionalUserInfo() will contain data // related to Google provider that the user signed in with. // authResult.getCredential() will contain the Google OAuth // credential. // authResult.getCredential().getAccessToken() will contain the // Google OAuth access token. // authResult.getCredential().getIdToken() contains the Google // OAuth ID token. } } });
O código abaixo mostra um exemplo completo de login em um usuário de vários fatores:
Kotlin
FirebaseAuth.getInstance()
.signInWithEmailAndPassword(email, password)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
// User is not enrolled with a second factor and is successfully
// signed in.
// ...
return@addOnCompleteListener
}
if (task.exception is FirebaseAuthMultiFactorException) {
val multiFactorResolver =
(task.exception as FirebaseAuthMultiFactorException).resolver
// Ask user which second factor to use. Then, get
// the selected hint:
val selectedHint =
multiFactorResolver.hints[selectedIndex] as PhoneMultiFactorInfo
// Send the SMS verification code.
PhoneAuthProvider.verifyPhoneNumber(
PhoneAuthOptions.newBuilder()
.setActivity(this)
.setMultiFactorSession(multiFactorResolver.session)
.setMultiFactorHint(selectedHint)
.setCallbacks(generateCallbacks())
.setTimeout(30L, TimeUnit.SECONDS)
.build()
)
// Ask user for the SMS verification code, then use it to get
// a PhoneAuthCredential:
val credential =
PhoneAuthProvider.getCredential(verificationId, verificationCode)
// Initialize a MultiFactorAssertion object with the
// PhoneAuthCredential.
val multiFactorAssertion: MultiFactorAssertion =
PhoneMultiFactorGenerator.getAssertion(credential)
// Complete sign-in.
multiFactorResolver
.resolveSignIn(multiFactorAssertion)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
// User successfully signed in with the
// second factor phone number.
}
// ...
}
} else {
// Handle other errors such as wrong password.
}
}
Java
FirebaseAuth.getInstance()
.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(
new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// User is not enrolled with a second factor and is successfully
// signed in.
// ...
return;
}
if (task.getException() instanceof FirebaseAuthMultiFactorException) {
FirebaseAuthMultiFactorException e =
(FirebaseAuthMultiFactorException) task.getException();
MultiFactorResolver multiFactorResolver = e.getResolver();
// Ask user which second factor to use.
MultiFactorInfo selectedHint =
multiFactorResolver.getHints().get(selectedIndex);
// Send the SMS verification code.
PhoneAuthProvider.verifyPhoneNumber(
PhoneAuthOptions.newBuilder()
.setActivity(this)
.setMultiFactorSession(multiFactorResolver.getSession())
.setMultiFactorHint(selectedHint)
.setCallbacks(generateCallbacks())
.setTimeout(30L, TimeUnit.SECONDS)
.build());
// Ask user for the SMS verification code.
PhoneAuthCredential credential =
PhoneAuthProvider.getCredential(verificationId, verificationCode);
// Initialize a MultiFactorAssertion object with the
// PhoneAuthCredential.
MultiFactorAssertion multiFactorAssertion =
PhoneMultiFactorGenerator.getAssertion(credential);
// Complete sign-in.
multiFactorResolver
.resolveSignIn(multiFactorAssertion)
.addOnCompleteListener(
new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// User successfully signed in with the
// second factor phone number.
}
// ...
}
});
} else {
// Handle other errors such as wrong password.
}
}
});
Parabéns! Você fez login com sucesso usando uma autenticação multifator.
A seguir
- Gerenciar usuários de vários fatores programaticamente com o Admin SDK.