Si actualizaste a Firebase Authentication with Identity Platform, puedes agregar la autenticación de varios factores mediante SMS a tu app de iOS.
La autenticación de varios factores aumenta la seguridad de tu app. Si bien los atacantes a menudo hackean las contraseñas y las cuentas de redes sociales, interceptar un mensaje de texto es más difícil.
Antes de comenzar
Habilita al menos un proveedor que admita la autenticación de varios factores. Todos los proveedores admiten la MFA, excepto la autenticación por teléfono, la autenticación anónima y Game Center de Apple.
Asegúrate de que en tu app se verifiquen los correos electrónicos de los usuarios. La MFA requiere la verificación por 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, agreguen un segundo factor para bloquear al propietario real.
Habilita la autenticación de varios factores
Abre la página Autenticación > Método de acceso de Firebase console.
En la sección Opciones avanzadas, habilita la Autenticación de varios factores mediante SMS.
También debes ingresar los números de teléfono con los que probarás la app. Si bien es opcional, se recomienda registrar los números de teléfono de prueba para evitar los límites durante el desarrollo.
Si aún no autorizas el dominio de tu app, agrégalo a la lista de entidades permitidas en la página Autenticación > Configuración de Firebase console.
Verifica tu app
Firebase necesita verificar que las solicitudes por SMS provengan de tu app. Puedes hacerlo de dos maneras:
Notificaciones silenciosas de APN: Cuando permites que un usuario acceda por primera vez, Firebase puede enviar una notificación push silenciosa al dispositivo del usuario. La autenticación puede continuar si la app recibe la notificación. Ten en cuenta que, a partir de iOS 8.0, no necesitas pedirle al usuario que permita las notificaciones push para usar este método.
Verificación de reCAPTCHA: Si no puedes enviar una notificación silenciosa (por ejemplo, porque el usuario inhabilitó la actualización en segundo plano o pruebas la app en el simulador de iOS), puedes usar reCAPTCHA. En muchos casos, el reCAPTCHA se resolverá automáticamente sin interacción de parte del usuario.
Usa notificaciones silenciosas
Para habilitar las notificaciones de APNs a fin de usarlas con Firebase, haz lo siguiente:
En Xcode, habilita las notificaciones push para el proyecto.
Sube la clave de autenticación de APNs con Firebase console (tus cambios se trasladarán automáticamente a Google Cloud Firebase). Si aún no tienes tu clave de autenticación de APNs, consulta Configura APNs con FCM para aprender a obtenerla.
Abre Firebase console.
Navega hasta Configuración de proyecto.
Selecciona la pestaña Cloud Messaging.
En Clave de autenticación de APN, en la sección Configuración de app para iOS, haz clic en Subir.
Selecciona tu clave.
Agrega el ID de la clave. Puedes encontrar el ID de la clave en Certificados, identificadores y perfiles en el Centro para miembros de Apple Developer.
Haz clic en Subir.
Si ya tienes un certificado de APN, puedes subirlo para completar el proceso.
Usa la verificación de reCAPTCHA
Para permitir que el SDK de cliente use reCAPTCHA, haz lo siguiente:
Abre la configuración de tu proyecto en Xcode.
Haz doble clic en el nombre del proyecto en la vista de árbol a la izquierda.
Selecciona tu app en la sección Targets.
Selecciona la pestaña Info.
Expande la sección URL Types.
Haz clic en el botón +.
Ingresa el ID de cliente revertido en el campo URL Schemes. Puedes encontrar este valor en el archivo de configuración
GoogleService-Info.plist
comoREVERSED_CLIENT_ID
.
Cuando se haya completado, la configuración debería ser similar a la siguiente:
De forma opcional, puedes personalizar la forma en que tu app presenta
SFSafariViewController
o UIWebView
cuando muestra el reCAPTCHA. Para
ello, crea una clase personalizada que cumpla con el protocolo FIRAuthUIDelegate
y pásala a verifyPhoneNumber:UIDelegate:completion:
.
Elige un patrón de inscripción
Puedes elegir si tu app requerirá una autenticación de varios factores, además de cómo y cuándo inscribir a tus usuarios. Entre los patrones comunes, se incluyen los siguientes:
Inscribir el segundo factor del usuario como parte del registro. Usa este método si tu app requiere la autenticación de varios factores para todos los usuarios. Considera que una cuenta debe tener una dirección de correo electrónico verificada para inscribir un segundo factor, por lo que tu flujo de registro deberá adaptarse a esto.
Ofrecer una opción que se puede omitir para inscribir un segundo factor durante el registro. Es posible que las apps que quieran fomentar el proceso de autenticación de varios factores, pero que no lo requieran, prefieran este enfoque.
Proporcionar la capacidad de agregar un segundo factor desde la página de administración de la cuenta o el perfil del usuario, en lugar de la pantalla de registro. Esto minimiza la fricción durante el proceso de registro y, a la vez, permite que la autenticación de varios factores esté disponible para los usuarios sensibles a la seguridad.
Requiere agregar un segundo factor de manera incremental cuando el usuario quiera acceder a las funciones con requisitos de seguridad mayores.
Inscribe un segundo factor
Si quieres inscribir un nuevo factor secundario para un usuario, haz lo siguiente:
Vuelve a autenticar al usuario.
Pídele al usuario que ingrese su número de teléfono.
Obtén una sesión de varios factores para el usuario:
Swift
authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in // ... }
Objective-C
[authResult.user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session, NSError * _Nullable error) { // ... }];
Envía un mensaje de verificación al teléfono del usuario. Asegúrate de que el número de teléfono tenga un formato
+
inicial y no otros signos de puntuación ni espacios en blanco (por ejemplo:+15105551234
)Swift
// Send SMS verification code. PhoneAuthProvider.provider().verifyPhoneNumber( phoneNumber, uiDelegate: nil, multiFactorSession: session) { (verificationId, error) in // verificationId will be needed for enrollment completion. }
Objective-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. }];
Si bien no es obligatorio, se recomienda informar con anticipación a los usuarios que recibirán un mensaje SMS y que se aplicarán las tarifas estándar.
Mediante el método
verifyPhoneNumber()
, se inicia el proceso de verificación de la app en segundo plano con una notificación push silenciosa. Si esta notificación no está disponible, se emite un desafío de reCAPTCHA en su lugar.Después de que se envíe el código SMS, pídele al usuario que lo verifique. Luego, usa su respuesta para compilar un
PhoneAuthCredential
:Swift
// Ask user for the verification code. Then: let credential = PhoneAuthProvider.provider().credential( withVerificationID: verificationId, verificationCode: verificationCode)
Objective-C
// Ask user for the SMS verification code. Then: FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID verificationCode:kPhoneSecondFactorVerificationCode];
Inicializa un objeto de aserción:
Swift
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
Objective-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
Completa la inscripción. De manera opcional, puedes especificar un nombre visible para el segundo factor. Esto resulta útil para usuarios con múltiples segundos factores, ya que el número de teléfono se enmascara durante el flujo de autenticación (por ejemplo, +1******1234).
Swift
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. user.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in // ... }
Objective-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) { // ... }];
En el siguiente código, se muestra un ejemplo completo de la inscripción de un segundo factor:
Swift
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
// ...
}
}
})
Objective-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) {
// ...
}];
}];
}];
¡Felicitaciones! Registraste correctamente un segundo factor de autenticación para un usuario.
Permite que los usuarios accedan con un segundo factor
Para que un usuario acceda con la verificación mediante SMS de dos factores, haz lo siguiente:
Permite que el usuario acceda con el primer factor y, luego, detecta un error que indique que se requiere una autenticación de varios factores. Este error contiene un agente de resolución, sugerencias sobre los segundos factores inscritos y una sesión subyacente, si el usuario se autenticó correctamente con el primer factor.
Por ejemplo, si el primer factor del usuario era un correo electrónico y una contraseña, haz lo siguiente:
Swift
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. } }
Objective-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. } }];
Si el primer factor del usuario es un proveedor federado, como OAuth, detecta el error después de llamar a
getCredentialWith()
.Si el usuario tiene múltiples factores secundarios inscritos, pregúntale cuál usará. Puedes obtener el número de teléfono enmascarado con
resolver.hints[selectedIndex].phoneNumber
y el nombre visible conresolver.hints[selectedIndex].displayName
.Swift
// 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. }
Objective-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. }
Envía un mensaje de verificación al teléfono del usuario:
Swift
// 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. }
Objective-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. } }];
Una vez que se envíe el código SMS, pídele al usuario que lo verifique y lo use para compilar un
PhoneAuthCredential
:Swift
// Ask user for the verification code. Then: let credential = PhoneAuthProvider.provider().credential( withVerificationID: verificationId!, verificationCode: verificationCodeFromUser)
Objective-C
// Ask user for the SMS verification code. Then: FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID verificationCode:verificationCodeFromUser];
Inicializa un objeto de aserción con la siguiente credencial:
Swift
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
Objective-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
Resuelve el acceso. Luego, puedes acceder al resultado del acceso original, en el que se incluyen los datos específicos del proveedor y las credenciales de autenticación estándar:
Swift
// 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. }
Objective-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. } }];
En el siguiente código, se muestra un ejemplo completo de acceso de un usuario de varios factores:
Swift
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.
}
}
}
}
}
Objective-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.
}
}];
}];
}
}];
¡Felicitaciones! Permitiste acceder a un usuario correctamente mediante la autenticación de varios factores.
¿Qué sigue?
- Administra usuarios de varios factores de forma programática con el Admin SDK.