Añadir autenticación multifactor a una aplicación iOS
En este documento se explica cómo añadir la autenticación multifactor por SMS a una aplicación iOS.
La autenticación multifactor aumenta la seguridad de tu aplicación. Aunque los atacantes suelen vulnerar las contraseñas y las cuentas de redes sociales, interceptar mensajes de texto resulta más difícil.
Antes de empezar
Habilita al menos un proveedor que admita la autenticación multifactor. 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 tu aplicación verifica los correos de los usuarios. La MFA requiere verificación por correo electrónico. De esta forma, se impide que agentes malintencionados se registren en un servicio con un correo que no les pertenece y, a continuación, bloqueen al propietario real añadiendo un segundo factor.
Habilitar la autenticación multifactor
Ve a la página MFA de Identity Platform en la Google Cloud consola.
Ve a la página MFAEn el cuadro Autenticación multifactor por SMS, haz clic en Habilitar.
Introduce los números de teléfono con los que vas a probar tu aplicación. Aunque es opcional, te recomendamos que registres números de teléfono de prueba para evitar la limitación durante el desarrollo.
Si aún no has autorizado el dominio de tu aplicación, añádelo a la lista de permitidos haciendo clic en Añadir dominio, a la derecha.
Haz clic en Guardar.
Verificar tu aplicación
Identity Platform debe verificar que las solicitudes de SMS proceden de tu aplicación. Puedes hacerlo de dos formas:
Notificaciones APNs silenciosas: cuando inicias la sesión de un usuario por primera vez, Identity Platform puede enviar una notificación push silenciosa al dispositivo del usuario. La autenticación puede continuar si la aplicación recibe la notificación. Ten en cuenta que, a partir de iOS 8.0, no es necesario pedir al usuario que permita las notificaciones push para usar este método.
Verificación reCAPTCHA: si no puedes enviar una notificación silenciosa (por ejemplo, porque el usuario ha inhabilitado la actualización en segundo plano o estás probando tu aplicación en el simulador de iOS), puedes usar reCAPTCHA. En muchos casos, reCAPTCHA se resolverá automáticamente sin que el usuario tenga que hacer nada.
Usar notificaciones silenciosas
Para habilitar las notificaciones de APNs para usarlas con Identity Platform, sigue estos pasos:
En Xcode, habilita las notificaciones push en tu proyecto.
Sube tu clave de autenticación de APNs mediante Firebase Console (los cambios se aplicarán automáticamente a Google Cloud Identity Platform). Si aún no tienes tu clave de autenticación de APNs, consulta el artículo Configurar APNs con FCM para saber cómo obtenerla.
Abre la consola de Firebase.
Ve a Configuración del proyecto.
Selecciona la pestaña Mensajería en la nube.
En Clave de autenticación de APNs, en la sección Configuración de la aplicación iOS, haz clic en Subir para subir tu clave de autenticación de desarrollo, tu clave de autenticación de producción o ambas. Se necesita al menos una.
Selecciona tu llave.
Añade el ID de la clave. Puedes encontrar el ID de clave en Certificates, Identifiers & Profiles (Certificados, identificadores y perfiles) del Centro de Miembros para Desarrolladores de Apple.
Haz clic en Subir.
Si ya tienes un certificado de APNs, puedes subirlo.
Usar la verificación reCAPTCHA
Para habilitar el SDK de cliente para usar reCAPTCHA, sigue estos pasos:
Abre la configuración del proyecto en Xcode.
Haz doble clic en el nombre del proyecto en la vista de árbol de la izquierda.
Selecciona tu aplicación en la sección Objetivos.
Selecciona la pestaña Información.
Despliega la sección Tipos de URL.
Haz clic en el botón +.
Introduce tu ID de cliente invertido en el campo URL Schemes (Esquemas de URL). Puedes encontrar este valor en el archivo de configuración
GoogleService-Info.plist
comoREVERSED_CLIENT_ID
.
Cuando haya terminado, la configuración debería ser similar a la siguiente:
También puedes personalizar la forma en que tu aplicación presenta el SFSafariViewController
o el UIWebView
al mostrar el reCAPTCHA. Para ello, crea una clase personalizada que se ajuste al protocolo FIRAuthUIDelegate
y pásala a verifyPhoneNumber:UIDelegate:completion:
.
Elegir un patrón de registro
Puedes elegir si tu aplicación requiere la autenticación multifactor y cómo y cuándo registrar a tus usuarios. Estos son algunos de los patrones habituales:
Registra el segundo factor del usuario durante el registro. Usa este método si tu aplicación requiere la autenticación multifactor para todos los usuarios. Ten en cuenta que una cuenta debe tener una dirección de correo verificada para registrar un segundo factor, por lo que tu flujo de registro deberá tenerlo en cuenta.
Ofrece una opción para omitir el registro de un segundo factor durante el registro. Las aplicaciones que quieran fomentar la autenticación multifactor, pero no exigirla, pueden preferir este método.
Ofrecer la posibilidad de añadir un segundo factor desde la página de gestión de la cuenta o el perfil del usuario, en lugar de desde la pantalla de registro. De esta forma, se minimizan las fricciones durante el proceso de registro y, al mismo tiempo, se ofrece la autenticación multifactor a los usuarios que se preocupan por la seguridad.
Exigir que se añada un segundo factor de forma gradual cuando el usuario quiera acceder a funciones con requisitos de seguridad más estrictos.
Registrar un segundo factor
Para registrar un nuevo factor secundario para un usuario, sigue estos pasos:
Vuelve a autenticar al usuario.
Pide al usuario que introduzca su número de teléfono.
Obtener una sesión multifactor 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 el formato
+
y no incluya ningún otro signo de puntuación ni espacio 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. }];
Aunque no es obligatorio, se recomienda informar a los usuarios de que van a recibir un mensaje SMS y de que se aplican tarifas estándar.
El método
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 emitirá una prueba reCAPTCHA.Una vez que se haya enviado el código por SMS, pide al usuario que lo verifique. Después, usa su respuesta para crear una
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 el registro. También puedes especificar un nombre visible para el segundo factor. Esto es útil para los usuarios que tienen varios segundos factores, ya que el número de teléfono se oculta 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) { // ... }];
El siguiente código muestra un ejemplo completo de cómo registrar 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) {
// ...
}];
}];
}];
¡Enhorabuena! Has registrado correctamente un segundo factor de autenticación para un usuario.
Inicio de sesión de usuarios con un segundo factor
Para iniciar la sesión de un usuario con la verificación por SMS de dos factores, sigue estos pasos:
Inicia sesión del usuario con su primer factor y, a continuación, detecta un error que indica que se requiere la autenticación multifactor. Este error contiene un elemento de resolución, sugerencias sobre los segundos factores registrados y una sesión subyacente que demuestra que el usuario se ha autenticado correctamente con el primer factor.
Por ejemplo, si el primer factor del usuario era un correo y una contraseña:
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 registrados varios factores secundarios, pregúntale cuál quiere usar. Puedes obtener el número de teléfono oculto 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 haya enviado el código por SMS, pide al usuario que lo verifique y lo utilice para crear 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 credencial:
Swift
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
Objective‑C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
Resuelve el inicio de sesión. Después, puedes acceder al resultado de inicio de sesión original, que incluye 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. } }];
El código siguiente muestra un ejemplo completo de inicio de sesión de un usuario con 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.
}
}];
}];
}
}];
¡Enhorabuena! Has iniciado sesión correctamente con un usuario mediante la autenticación multifactor.
Siguientes pasos
- Gestiona usuarios que utilicen la autenticación multifactor de forma programática con el SDK de administrador.