Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Adicione autenticação multifator ao seu aplicativo iOS

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Se você atualizou para o Firebase Authentication com Identity Platform, pode 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 geralmente comprometam senhas e contas sociais, interceptar uma mensagem de texto é mais difícil.

Antes de você começar

  1. Habilite pelo menos um provedor que ofereça suporte à autenticação multifator. Todos os provedores são compatíveis com MFA, exceto autenticação por telefone, autenticação anônima e Apple Game Center.

  2. Certifique-se de que seu aplicativo esteja verificando os e-mails dos usuários. A 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 seja deles e, em seguida, bloqueiem o verdadeiro proprietário adicionando um segundo fator.

Ativando a autenticação multifator

  1. Abra a página Autenticação > Método de login do Firebase console.

  2. Na seção Avançado , habilite a autenticação multifator por SMS .

    Você também deve inserir os números de telefone com os quais testará seu aplicativo. Embora seja opcional, é altamente recomendável registrar números de telefone de teste para evitar a limitação durante o desenvolvimento.

  3. 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 pode prosseguir se o aplicativo receber a notificação. Observe que a partir do iOS 8.0, você não precisa pedir ao usuário para permitir que notificações push usem esse método.

  • Verificação do reCAPTCHA : se você não puder enviar uma notificação silenciosa (por exemplo, porque o usuário desativou a atualização em segundo plano ou está testando seu aplicativo no simulador do iOS), você pode usar o reCAPTCHA. Em muitos casos, o reCAPTCHA se resolverá automaticamente sem interação do usuário.

Usando notificações silenciosas

Para ativar as notificações de APNs para uso com o Firebase:

  1. No Xcode, habilite as notificações push para seu projeto.

  2. 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 tiver sua chave de autenticação de APNs, consulte Configurando APNs com FCM para saber como obtê-la.

    1. Abra o Console do Firebase .

    2. Navegue até Configurações do projeto .

    3. Selecione a guia Cloud Messaging .

    4. Em Chave de autenticação de APNs , na seção de configuração do aplicativo iOS , clique em Carregar .

    5. Selecione sua chave.

    6. Adicione o ID da chave para a chave. Você pode encontrar o ID da chave em Certificados, Identificadores e Perfis no Apple Developer Member Center .

    7. Clique em Carregar .

Se você já tiver um certificado de APNs, poderá fazer upload do certificado.

Usando a verificação reCAPTCHA

Para permitir que o SDK do cliente use o reCAPTCHA:

  1. Abra a configuração do seu projeto no Xcode.

  2. Clique duas vezes no nome do projeto na visualização em árvore à esquerda.

  3. Selecione seu aplicativo na seção Destinos .

  4. Selecione a guia Informações .

  5. Expanda a seção Tipos de URL .

  6. Clique no botão + .

  7. Insira seu ID de cliente revertido no campo Esquemas de URL . Você pode encontrar esse valor listado no arquivo de configuração GoogleService-Info.plist como REVERSED_CLIENT_ID .

Quando concluída, sua configuração deve ser semelhante à seguinte:

Esquemas personalizados

Opcionalmente, você pode personalizar a maneira 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:

  • Inscrever 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 registrar um segundo fator, portanto, seu fluxo de registro terá que 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 da conta do usuário ou da página de gerenciamento de perfil, em vez da tela de inscrição. Isso minimiza o atrito durante o processo de registro, enquanto ainda disponibiliza a autenticação multifator para usuários sensíveis à segurança.

  • Exigir a adição de um segundo fator de forma incremental quando o usuário deseja acessar recursos com requisitos de segurança maiores.

Inscrevendo um segundo fator

Para inscrever um novo fator secundário para um usuário:

  1. Re-autentique o usuário.

  2. Peça ao usuário que digite seu número de telefone.

  3. Obtenha uma sessão multifator 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) {
        // ...
    }];
    
  4. 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 sem 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 aos usuários com antecedência que eles receberão uma mensagem SMS e que as taxas padrão se aplicam.

    O método verifyPhoneNumber() inicia o processo de verificação do aplicativo em segundo plano usando a notificação push silenciosa. Se a notificação por push silenciosa não estiver disponível, um desafio reCAPTCHA será emitido.

  5. Assim que o código SMS for enviado, peça ao usuário para verificar o código. Em seguida, use a resposta 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];
    
  6. Inicialize um objeto de declaração:

    Rápido

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    Objetivo-C

    FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  7. 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 fatores de segundo, 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 sucesso 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 por SMS de dois fatores:

  1. Conecte o usuário com seu primeiro fator e, em seguida, detecte um erro indicando que a autenticação multifator é necessária. Esse 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 êxito com o primeiro fator.

    Por exemplo, se o primeiro fator do usuário foi um e-mail 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() .

  2. Se o usuário tiver vários fatores secundários registrados, pergunte qual deles usar. Você pode obter o número de telefone mascarado com resolver.hints[selectedIndex].phoneNumber e o nome de exibição com resolver.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 {
      // Unsupported second factor.
      // Note that only phone second factors are currently supported.
    }
    

    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 {
      // Unsupported second factor.
      // Note that only phone second factors are currently supported.
    }
    
  3. 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.
        }
    }];
    
  4. Depois 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];
    
  5. Inicialize um objeto de declaração com a credencial:

    Rápido

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    Objetivo-C

    FIRMultiFactorAssertion *assertion =
        [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  6. Resolva o login. Você pode 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 sucesso em um usuário usando a autenticação multifator.

Qual é o próximo