Únete de manera presencial y en línea a Firebase Summit el 18 de octubre de 2022. Descubre cómo Firebase puede ayudarte a acelerar el desarrollo de apps, a lanzar la tuya con confianza y a escalar con facilidad. Regístrate ahora

Agregue autenticación multifactor a su aplicación iOS

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Si actualizó a Firebase Authentication con Identity Platform, puede agregar la autenticación multifactor por SMS a su aplicación de iOS.

La autenticación multifactor aumenta la seguridad de su aplicación. Si bien los atacantes a menudo comprometen contraseñas y cuentas sociales, interceptar un mensaje de texto es más difícil.

Antes de que empieces

  1. Habilite al menos un proveedor que admita la autenticación multifactor. Todos los proveedores admiten MFA, excepto la autenticación telefónica, la autenticación anónima y Apple Game Center.

  2. Asegúrese de que su aplicación esté verificando los correos electrónicos de los usuarios. MFA requiere verificación de correo electrónico. Esto evita que los actores maliciosos se registren en un servicio con un correo electrónico que no les pertenece y luego bloqueen al propietario real al agregar un segundo factor.

Habilitación de la autenticación multifactor

  1. Abra la página Autenticación > Método de inicio de sesión de Firebase console.

  2. En la sección Avanzado , habilite la Autenticación multifactor SMS .

    También debe ingresar los números de teléfono con los que probará su aplicación. Si bien es opcional, se recomienda encarecidamente registrar números de teléfono de prueba para evitar limitaciones durante el desarrollo.

  3. Si aún no autorizó el dominio de su aplicación, agréguelo a la lista de permitidos en la página Autenticación > Configuración de Firebase console.

Verificando tu aplicación

Firebase necesita verificar que las solicitudes de SMS provengan de su aplicación. Puede hacer esto de dos maneras:

  • Notificaciones silenciosas de APN : cuando inicia sesión con un usuario por primera vez, Firebase puede enviar una notificación push silenciosa al dispositivo del usuario. La autenticación puede continuar si la aplicación recibe la notificación. Tenga en cuenta que, a partir de iOS 8.0, no necesita pedirle al usuario que permita las notificaciones automáticas para usar este método.

  • Verificación de reCAPTCHA : si no puede enviar una notificación silenciosa (por ejemplo, porque el usuario ha deshabilitado la actualización en segundo plano o está probando su aplicación en el simulador de iOS), puede usar reCAPTCHA. En muchos casos, el reCAPTCHA se resolverá automáticamente sin interacción del usuario.

Uso de notificaciones silenciosas

Para habilitar las notificaciones de APN para su uso con Firebase:

  1. En Xcode, habilite las notificaciones push para su proyecto.

  2. Cargue su clave de autenticación de APN con Firebase Console (sus cambios se transferirán automáticamente a Google Cloud Firebase). Si aún no tiene su clave de autenticación de APN, consulte Configuración de APN con FCM para obtener información sobre cómo obtenerla.

    1. Abre la consola de Firebase .

    2. Vaya a Configuración del proyecto .

    3. Seleccione la pestaña Mensajería en la nube .

    4. En la clave de autenticación de APN, en la sección de configuración de la aplicación iOS , haga clic en Cargar .

    5. Seleccione su clave.

    6. Agregue el ID de clave para la clave. Puede encontrar el ID de clave en Certificados, identificadores y perfiles en el Centro de miembros para desarrolladores de Apple .

    7. Haga clic en Cargar .

Si ya tiene un certificado APNs, puede cargar el certificado en su lugar.

Usando la verificación reCAPTCHA

Para permitir que el SDK del cliente use reCAPTCHA:

  1. Abra la configuración de su proyecto en Xcode.

  2. Haga doble clic en el nombre del proyecto en la vista de árbol de la izquierda.

  3. Seleccione su aplicación en la sección Objetivos .

  4. Seleccione la pestaña Información .

  5. Expanda la sección Tipos de URL .

  6. Haga clic en el botón + .

  7. Ingrese su ID de cliente invertida en el campo Esquemas de URL . Puede encontrar este valor en el archivo de configuración GoogleService-Info.plist como REVERSED_CLIENT_ID .

Cuando se complete, su configuración debería ser similar a la siguiente:

esquemas personalizados

Opcionalmente, puede personalizar la forma en que su aplicación presenta SFSafariViewController o UIWebView cuando muestra reCAPTCHA. Para hacer esto, cree una clase personalizada que se ajuste al protocolo FIRAuthUIDelegate y verifyPhoneNumber:UIDelegate:completion: .

Elegir un patrón de inscripción

Puede elegir si su aplicación requiere autenticación multifactor y cómo y cuándo inscribir a sus usuarios. Algunos patrones comunes incluyen:

  • Inscriba el segundo factor del usuario como parte del registro. Utilice este método si su aplicación requiere autenticación multifactor para todos los usuarios. Tenga en cuenta que una cuenta debe tener una dirección de correo electrónico verificada para inscribir un segundo factor, por lo que su flujo de registro deberá adaptarse a esto.

  • Ofrezca una opción saltable para inscribir un segundo factor durante el registro. Las aplicaciones que desean fomentar, pero no exigir, la autenticación multifactor pueden preferir este enfoque.

  • Proporcione la capacidad de agregar un segundo factor desde la cuenta del usuario o la página de administración del perfil, en lugar de la pantalla de registro. Esto minimiza la fricción durante el proceso de registro, al mismo tiempo que hace que la autenticación de múltiples factores esté disponible para usuarios sensibles a la seguridad.

  • Requerir agregar un segundo factor de forma incremental cuando el usuario desee acceder a funciones con mayores requisitos de seguridad.

Inscripción de un segundo factor

Para inscribir un nuevo factor secundario para un usuario:

  1. Vuelva a autenticar al usuario.

  2. Pida al usuario que introduzca su número de teléfono.

  3. Obtenga una sesión multifactor para el usuario:

    Rápido

    authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in
      // ...
    }
    

    C objetivo

    [authResult.user.multiFactor
      getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session,
                                NSError * _Nullable error) {
        // ...
    }];
    
  4. Envía un mensaje de verificación al teléfono del usuario. Asegúrese de que el número de teléfono esté formateado con un + inicial y sin otros signos de puntuación o espacios en blanco (por ejemplo: +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.
    }
    

    C objetivo

    // 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.
    }];
    

    Si bien no es obligatorio, es una buena práctica informar a los usuarios de antemano que recibirán un mensaje SMS y que se aplican las tarifas estándar.

    El verifyPhoneNumber() inicia el proceso de verificación de la aplicación en segundo plano mediante una notificación push silenciosa. Si la notificación push silenciosa no está disponible, se emite un desafío reCAPTCHA en su lugar.

  5. Una vez que se envía el código SMS, solicite al usuario que verifique el código. Luego, usa su respuesta para crear una PhoneAuthCredential :

    Rápido

    // Ask user for the verification code. Then:
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId,
      verificationCode: verificationCode)
    

    C objetivo

    // Ask user for the SMS verification code. Then:
    FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider
                                           credentialWithVerificationID:verificationID
                                           verificationCode:kPhoneSecondFactorVerificationCode];
    
  6. Inicializar un objeto de aserción:

    Rápido

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    C objetivo

    FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  7. Completa la inscripción. Opcionalmente, puede especificar un nombre para mostrar para el segundo factor. Esto es útil para usuarios con factores de varios segundos, ya que el número de teléfono se enmascara durante el flujo de autenticación (por ejemplo, +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
      // ...
    }
    

    C objetivo

    // 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) {
        // ...
    }];
    

El siguiente código muestra un ejemplo completo de cómo inscribir un segundo factor:

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
      // ...
    }
  }
})

C objetivo

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) {
            // ...
        }];
    }];
}];

¡Felicidades! Ha registrado correctamente un segundo factor de autenticación para un usuario.

Inicio de sesión de usuarios con un segundo factor

Para iniciar sesión en un usuario con verificación de SMS de dos factores:

  1. Inicie sesión con el usuario con su primer factor, luego detecte un error que indica que se requiere autenticación de múltiples factores. Este error contiene una resolución, sugerencias sobre los segundos factores inscritos y una sesión subyacente que prueba que el usuario se autenticó correctamente con el primer factor.

    Por ejemplo, si el primer factor del usuario fue un correo electrónico y una contraseña:

    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.
      }
    }
    

    C objetivo

    [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.
        }
    }];
    

    Si el primer factor del usuario es un proveedor federado, como OAuth, detecte el error después de llamar a getCredentialWith() .

  2. Si el usuario tiene varios factores secundarios inscritos, pregúntele cuál usar. Puede obtener el número de teléfono enmascarado con resolver.hints[selectedIndex].phoneNumber y el nombre para mostrar con 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.
    }
    

    C objetivo

    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. Envía un mensaje de verificación al teléfono del usuario:

    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.
    }
    

    C objetivo

    // 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. Una vez que se envía el código SMS, pídale al usuario que verifique el código y utilícelo para crear una PhoneAuthCredential :

    Rápido

    // Ask user for the verification code. Then:
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId!,
      verificationCode: verificationCodeFromUser)
    

    C objetivo

    // Ask user for the SMS verification code. Then:
    FIRPhoneAuthCredential *credential =
        [FIRPhoneAuthProvider.provider
          credentialWithVerificationID:verificationID
                      verificationCode:verificationCodeFromUser];
    
  5. Inicialice un objeto de aserción con la credencial:

    Rápido

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    C objetivo

    FIRMultiFactorAssertion *assertion =
        [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  6. Resolver el inicio de sesión. A continuación, puede acceder al resultado de inicio de sesión original, que incluye los datos estándar específicos del proveedor y las credenciales de autenticación:

    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.
    }
    

    C objetivo

    // 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.
        }
    }];
    

El siguiente código muestra un ejemplo completo del inicio de sesión de un usuario de múltiples factores:

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.
        }
      }
    }
  }
}

C objetivo

[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.
                }
            }];
        }];
    }
}];

¡Felicidades! Has iniciado sesión con éxito en un usuario mediante la autenticación multifactor.

Que sigue