Se você fez upgrade para o Firebase Authentication com Identity Platform, poderá adicionar a autenticação multifator por SMS ao seu aplicativo iOS.
A autenticação multifator aumenta a segurança do seu aplicativo. Embora os invasores frequentemente comprometam senhas e contas sociais, interceptar uma mensagem de texto é mais difícil.
Antes de você começar
Habilite pelo menos um provedor que ofereça suporte à autenticação multifator. Todos os provedores oferecem suporte a MFA, exceto autenticação por telefone, autenticação anônima e Apple Game Center.
Certifique-se de que seu aplicativo esteja verificando os e-mails dos usuários. A MFA requer verificação de e-mail. Isso evita que atores mal-intencionados se registrem em um serviço com um e-mail que não sejam de sua propriedade e, em seguida, bloqueiem o proprietário real adicionando um segundo fator.
Habilitando a autenticação multifator
Abra a página Autenticação > Método de login do console do Firebase.
Na seção Avançado , habilite a autenticação multifator de SMS .
Você também deve inserir os números de telefone com os quais testará seu aplicativo. Embora opcional, é altamente recomendável registrar números de telefone de teste para evitar limitações durante o desenvolvimento.
Se você ainda não autorizou o domínio do seu aplicativo, adicione-o à lista de permissões na página Autenticação > Configurações do console do Firebase.
Verificando seu aplicativo
O Firebase precisa verificar se as solicitações de SMS vêm do seu aplicativo. Você pode fazer isso de duas maneiras:
Notificações silenciosas de APNs : quando você faz login de um usuário pela primeira vez, o Firebase pode enviar uma notificação push silenciosa para o dispositivo do usuário. A autenticação poderá prosseguir se o aplicativo receber a notificação. Observe que a partir do iOS 8.0, você não precisa solicitar ao usuário que permita notificações push para usar esse método.
Verificação reCAPTCHA : se você não conseguir enviar uma notificação silenciosa (por exemplo, porque o usuário desativou a atualização em segundo plano ou você está testando seu aplicativo no simulador iOS), poderá usar o reCAPTCHA. Em muitos casos, o reCAPTCHA se resolverá automaticamente, sem interação do usuário.
Usando notificações silenciosas
Para ativar notificações de APNs para uso com o Firebase:
No Xcode, habilite notificações push para seu projeto.
Faça upload da sua chave de autenticação de APNs usando o Firebase Console (suas alterações serão transferidas automaticamente para o Google Cloud Firebase). Se você ainda não tem sua chave de autenticação de APNs, consulte Configurando APNs com FCM para saber como obtê-la.
Abra o Console do Firebase .
Navegue até Configurações do projeto .
Selecione a guia Mensagens na nuvem .
Em Chave de autenticação de APNs , na seção de configuração do aplicativo iOS , clique em Carregar .
Selecione sua chave.
Adicione o ID da chave. Você pode encontrar o ID da chave em Certificados, identificadores e perfis no Apple Developer Member Center .
Clique em Carregar .
Se você já tiver um certificado de APNs, poderá fazer upload do certificado.
Usando verificação reCAPTCHA
Para permitir que o SDK do cliente use o reCAPTCHA:
Abra a configuração do seu projeto no Xcode.
Clique duas vezes no nome do projeto na visualização em árvore esquerda.
Selecione seu aplicativo na seção Destinos .
Selecione a guia Informações .
Expanda a seção Tipos de URL .
Clique no botão + .
Insira seu ID de cliente invertido no campo Esquemas de URL . Você pode encontrar esse valor listado no arquivo de configuração
GoogleService-Info.plist
comoREVERSED_CLIENT_ID
.
Quando concluída, sua configuração deverá ser semelhante à seguinte:
Opcionalmente, você pode personalizar a forma como seu aplicativo apresenta o SFSafariViewController
ou UIWebView
ao exibir o reCAPTCHA. Para fazer isso, crie uma classe personalizada que esteja em conformidade com o protocolo FIRAuthUIDelegate
e passe-a para verifyPhoneNumber:UIDelegate:completion:
.
Escolhendo um padrão de inscrição
Você pode escolher se seu aplicativo requer autenticação multifator e como e quando inscrever seus usuários. Alguns padrões comuns incluem:
Inscreva o segundo fator do usuário como parte do registro. Use este método se seu aplicativo exigir autenticação multifator para todos os usuários. Observe que uma conta deve ter um endereço de e-mail verificado para inscrever um segundo fator, portanto, seu fluxo de registro deverá acomodar isso.
Ofereça uma opção ignorável para inscrever um segundo fator durante o registro. Os aplicativos que desejam incentivar, mas não exigem, a autenticação multifator podem preferir essa abordagem.
Forneça a capacidade de adicionar um segundo fator na conta do usuário ou na página de gerenciamento de perfil, 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 sensíveis à segurança.
Exigir a adição incremental de um segundo fator quando o usuário desejar acessar recursos com maiores requisitos de segurança.
Inscrevendo um segundo fator
Para inscrever um novo fator secundário para um usuário:
Autentique novamente o usuário.
Peça ao usuário que insira seu número de telefone.
Obtenha uma sessão multifatorial para o usuário:
Rápido
authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in // ... }
Objetivo-C
[authResult.user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session, NSError * _Nullable error) { // ... }];
Envie uma mensagem de verificação para o telefone do usuário. Certifique-se de que o número de telefone esteja formatado com um
+
inicial e nenhuma outra pontuação ou espaço em branco (por exemplo:+15105551234
)Rápido
// Send SMS verification code. PhoneAuthProvider.provider().verifyPhoneNumber( phoneNumber, uiDelegate: nil, multiFactorSession: session) { (verificationId, error) in // verificationId will be needed for enrollment completion. }
Objetivo-C
// Send SMS verification code. [FIRPhoneAuthProvider.provider verifyPhoneNumber:phoneNumber UIDelegate:nil multiFactorSession:session completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { // verificationId will be needed for enrollment completion. }];
Embora não seja obrigatório, é uma prática recomendada informar antecipadamente aos usuários que eles receberão uma mensagem SMS e que serão aplicadas taxas padrão.
O método
verifyPhoneNumber()
inicia o processo de verificação do aplicativo em segundo plano usando notificação push silenciosa. Se a notificação push silenciosa não estiver disponível, um desafio reCAPTCHA será emitido.Assim que o código SMS for enviado, peça ao usuário para verificar o código. Em seguida, use a resposta deles para criar um
PhoneAuthCredential
:Rápido
// Ask user for the verification code. Then: let credential = PhoneAuthProvider.provider().credential( withVerificationID: verificationId, verificationCode: verificationCode)
Objetivo-C
// Ask user for the SMS verification code. Then: FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID verificationCode:kPhoneSecondFactorVerificationCode];
Inicialize um objeto de asserção:
Rápido
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
Objetivo-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
Conclua a inscrição. Opcionalmente, você pode especificar um nome de exibição para o segundo fator. Isso é útil para usuários com vários segundos fatores, pois o número de telefone é mascarado durante o fluxo de autenticação (por exemplo, +1******1234).
Rápido
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. user.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in // ... }
Objetivo-C
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. [authResult.user.multiFactor enrollWithAssertion:assertion displayName:nil completion:^(NSError * _Nullable error) { // ... }];
O código abaixo mostra um exemplo completo de inscrição de um segundo fator:
Rápido
let user = Auth.auth().currentUser
user?.multiFactor.getSessionWithCompletion({ (session, error) in
// Send SMS verification code.
PhoneAuthProvider.provider().verifyPhoneNumber(
phoneNumber,
uiDelegate: nil,
multiFactorSession: session
) { (verificationId, error) in
// verificationId will be needed for enrollment completion.
// Ask user for the verification code.
let credential = PhoneAuthProvider.provider().credential(
withVerificationID: verificationId!,
verificationCode: phoneSecondFactorVerificationCode)
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
// Complete enrollment. This will update the underlying tokens
// and trigger ID token change listener.
user?.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in
// ...
}
}
})
Objetivo-C
FIRUser *user = FIRAuth.auth.currentUser;
[user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session,
NSError * _Nullable error) {
// Send SMS verification code.
[FIRPhoneAuthProvider.provider
verifyPhoneNumber:phoneNumber
UIDelegate:nil
multiFactorSession:session
completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
// verificationId will be needed for enrollment completion.
// Ask user for the verification code.
// ...
// Then:
FIRPhoneAuthCredential *credential =
[FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID
verificationCode:kPhoneSecondFactorVerificationCode];
FIRMultiFactorAssertion *assertion =
[FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
// Complete enrollment. This will update the underlying tokens
// and trigger ID token change listener.
[user.multiFactor enrollWithAssertion:assertion
displayName:displayName
completion:^(NSError * _Nullable error) {
// ...
}];
}];
}];
Parabéns! Você registrou com êxito um segundo fator de autenticação para um usuário.
Conectando usuários com um segundo fator
Para fazer login de um usuário com verificação SMS de dois fatores:
Faça login do usuário com seu primeiro fator e, em seguida, detecte um erro indicando que a autenticação multifator é necessária. Este erro contém um resolvedor, dicas sobre os segundos fatores registrados e uma sessão subjacente que prova que o usuário foi autenticado com sucesso com o primeiro fator.
Por exemplo, se o primeiro fator do usuário for email e senha:
Rápido
Auth.auth().signIn( withEmail: email, password: password ) { (result, error) in let authError = error as NSError if authError?.code == AuthErrorCode.secondFactorRequired.rawValue { // The user is a multi-factor user. Second factor challenge is required. let resolver = authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver // ... } else { // Handle other errors such as wrong password. } }
Objetivo-C
[FIRAuth.auth signInWithEmail:email password:password completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) { // User is not enrolled with a second factor and is successfully signed in. // ... } else { // The user is a multi-factor user. Second factor challenge is required. } }];
Se o primeiro fator do usuário for um provedor federado, como OAuth, detecte o erro após chamar
getCredentialWith()
.Se o usuário tiver vários fatores secundários inscritos, pergunte qual deles usar. Você pode obter o número de telefone mascarado com
resolver.hints[selectedIndex].phoneNumber
e o nome de exibição comresolver.hints[selectedIndex].displayName
.Rápido
// Ask user which second factor to use. Then: if resolver.hints[selectedIndex].factorID == PhoneMultiFactorID { // User selected a phone second factor. // ... } else if resolver.hints[selectedIndex].factorID == TotpMultiFactorID { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }
Objetivo-C
FIRMultiFactorResolver *resolver = (FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey]; // Ask user which second factor to use. Then: FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex]; if (hint.factorID == FIRPhoneMultiFactorID) { // User selected a phone second factor. // ... } else if (hint.factorID == FIRTOTPMultiFactorID) { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }
Envie uma mensagem de verificação para o telefone do usuário:
Rápido
// Send SMS verification code. let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo PhoneAuthProvider.provider().verifyPhoneNumber( with: hint, uiDelegate: nil, multiFactorSession: resolver.session ) { (verificationId, error) in // verificationId will be needed for sign-in completion. }
Objetivo-C
// Send SMS verification code [FIRPhoneAuthProvider.provider verifyPhoneNumberWithMultiFactorInfo:hint UIDelegate:nil multiFactorSession:resolver.session completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { if (error != nil) { // Failed to verify phone number. } }];
Assim que o código SMS for enviado, peça ao usuário para verificar o código e usá-lo para criar um
PhoneAuthCredential
:Rápido
// Ask user for the verification code. Then: let credential = PhoneAuthProvider.provider().credential( withVerificationID: verificationId!, verificationCode: verificationCodeFromUser)
Objetivo-C
// Ask user for the SMS verification code. Then: FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID verificationCode:verificationCodeFromUser];
Inicialize um objeto de asserção com a credencial:
Rápido
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
Objetivo-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
Resolva o login. Você pode então acessar o resultado de login original, que inclui os dados padrão específicos do provedor e as credenciais de autenticação:
Rápido
// Complete sign-in. This will also trigger the Auth state listeners. resolver.resolveSignIn(with: assertion) { (authResult, error) in // authResult will also contain the user, additionalUserInfo, 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.additionalUserInfo will contain data related to Google provider that // the user signed in with. // user.credential contains the Google OAuth credential. // user.credential.accessToken contains the Google OAuth access token. // user.credential.idToken contains the Google OAuth ID token. }
Objetivo-C
// Complete sign-in. [resolver resolveSignInWithAssertion:assertion completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error != nil) { // User successfully signed in with the second factor phone number. } }];
O código abaixo mostra um exemplo completo de login de um usuário multifator:
Rápido
Auth.auth().signIn(
withEmail: email,
password: password
) { (result, error) in
let authError = error as NSError?
if authError?.code == AuthErrorCode.secondFactorRequired.rawValue {
let resolver =
authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
// Ask user which second factor to use.
// ...
// Then:
let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo
// Send SMS verification code
PhoneAuthProvider.provider().verifyPhoneNumber(
with: hint,
uiDelegate: nil,
multiFactorSession: resolver.session
) { (verificationId, error) in
if error != nil {
// Failed to verify phone number.
}
// Ask user for the SMS verification code.
// ...
// Then:
let credential = PhoneAuthProvider.provider().credential(
withVerificationID: verificationId!,
verificationCode: verificationCodeFromUser)
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
// Complete sign-in.
resolver.resolveSignIn(with: assertion) { (authResult, error) in
if error != nil {
// User successfully signed in with the second factor phone number.
}
}
}
}
}
Objetivo-C
[FIRAuth.auth signInWithEmail:email
password:password
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) {
// User is not enrolled with a second factor and is successfully signed in.
// ...
} else {
FIRMultiFactorResolver *resolver =
(FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];
// Ask user which second factor to use.
// ...
// Then:
FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex];
// Send SMS verification code
[FIRPhoneAuthProvider.provider
verifyPhoneNumberWithMultiFactorInfo:hint
UIDelegate:nil
multiFactorSession:resolver.session
completion:^(NSString * _Nullable verificationID,
NSError * _Nullable error) {
if (error != nil) {
// Failed to verify phone number.
}
// Ask user for the SMS verification code.
// ...
// Then:
FIRPhoneAuthCredential *credential =
[FIRPhoneAuthProvider.provider
credentialWithVerificationID:verificationID
verificationCode:kPhoneSecondFactorVerificationCode];
FIRMultiFactorAssertion *assertion =
[FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
// Complete sign-in.
[resolver resolveSignInWithAssertion:assertion
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
if (error != nil) {
// User successfully signed in with the second factor phone number.
}
}];
}];
}
}];
Parabéns! Você fez login com êxito em um usuário usando autenticação multifator.
Qual é o próximo
- Gerencie usuários multifatoriais de maneira programática com o Admin SDK.