Agregue autenticación multifactor a su aplicación Flutter

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

La autenticación multifactor (MFA) aumenta la seguridad de su aplicación. Si bien los atacantes suelen comprometer 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 verifique los correos electrónicos de los usuarios. MFA requiere verificación por correo electrónico. Esto evita que actores maliciosos se registren en un servicio con un correo electrónico que no les pertenece y luego bloqueen al propietario real agregando un segundo factor.

  3. Android : si aún no has configurado el hash SHA-256 de tu aplicación en Firebase console , hazlo. Consulte Autenticar a su cliente para obtener información sobre cómo encontrar el hash SHA-256 de su aplicación.

  4. iOS : en Xcode, habilite las notificaciones automáticas para su proyecto y asegúrese de que su clave de autenticación de APN esté configurada con Firebase Cloud Messaging (FCM) . Además, debe habilitar los modos en segundo plano para notificaciones remotas. Para ver una explicación detallada de este paso, consulte la documentación de autenticación de teléfono de Firebase iOS .

  5. Web : asegúrese de haber agregado el dominio de su aplicación en Firebase console , en Dominios de redirección de OAuth .

Habilitar 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 por SMS .

    También debes ingresar los números de teléfono con los que probarás tu 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 ha autorizado el dominio de su aplicación, agréguelo a la lista de permitidos en la página Autenticación > Configuración de Firebase console.

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.

  • Ofrezca una opción que se pueda omitir para inscribir un segundo factor durante el registro. Las aplicaciones que quieran fomentar, pero no exigir, la autenticación multifactor podrían preferir este enfoque.

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

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

Inscribir un segundo factor

Para inscribir un nuevo factor secundario para un usuario:

  1. Vuelva a autenticar al usuario.

  2. Solicite al usuario que ingrese su número de teléfono.

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

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. Verifica el número de teléfono con una sesión multifactor y tus devoluciones de llamada:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: multiFactorSession,
      phoneNumber: phoneNumber,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // The SMS verification code has been sent to the provided phone number.
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    ); 
    
  5. Una vez enviado el código SMS, solicite al usuario que verifique el código:

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. Completa la inscripción:

    await user.multiFactor.enroll(
      PhoneMultiFactorGenerator.getAssertion(
        credential,
      ),
    );
    

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

  final session = await user.multiFactor.getSession();
  final auth = FirebaseAuth.instance;
  await auth.verifyPhoneNumber(
    multiFactorSession: session,
    phoneNumber: phoneController.text,
    verificationCompleted: (_) {},
    verificationFailed: (_) {},
    codeSent: (String verificationId, int? resendToken) async {
      // See `firebase_auth` example app for a method of retrieving user's sms code: 
      // https://github.com/firebase/flutterfire/blob/master/packages/firebase_auth/firebase_auth/example/lib/auth.dart#L591
      final smsCode = await getSmsCodeFromUser(context);

      if (smsCode != null) {
        // Create a PhoneAuthCredential with the code
        final credential = PhoneAuthProvider.credential(
          verificationId: verificationId,
          smsCode: smsCode,
        );

        try {
          await user.multiFactor.enroll(
            PhoneMultiFactorGenerator.getAssertion(
              credential,
            ),
          );
        } on FirebaseAuthException catch (e) {
          print(e.message);
        }
      }
    },
    codeAutoRetrievalTimeout: (_) {},
  );

¡Felicidades! Registró exitosamente un segundo factor de autenticación para un usuario.

Iniciar sesión de usuarios con un segundo factor

Para iniciar sesión como usuario con verificación por SMS de dos factores:

  1. Inicie sesión en el usuario con su primer factor y luego detecte la excepción FirebaseAuthMultiFactorException . Este error contiene un solucionador, que puede utilizar para obtener los segundos factores registrados del usuario. También contiene una sesión subyacente que demuestra que el usuario se autenticó exitosamente con su primer factor.

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

    try {
      await _auth.signInWithEmailAndPassword(
          email: emailController.text,
          password: passwordController.text,
      );
      // User is not enrolled with a second factor and is successfully
      // signed in.
      // ...
    } on FirebaseAuthMultiFactorException catch (e) {
      // The user is a multi-factor user. Second factor challenge is required
      final resolver = e.resolver
      // ...
    }
    
  2. Si el usuario tiene varios factores secundarios inscritos, pregúntale cuál usar:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Envía un mensaje de verificación al teléfono del usuario con la pista y la sesión multifactor:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. Llame a resolver.resolveSignIn() para completar la autenticación secundaria:

    final smsCode = await getSmsCodeFromUser(context);
    if (smsCode != null) {
      // Create a PhoneAuthCredential with the code
      final credential = PhoneAuthProvider.credential(
        verificationId: verificationId,
        smsCode: smsCode,
      );
    
      try {
        await e.resolver.resolveSignIn(
          PhoneMultiFactorGenerator.getAssertion(credential)
        );
      } on FirebaseAuthException catch (e) {
        print(e.message);
      }
    }
    

El siguiente código muestra un ejemplo completo de cómo iniciar sesión como usuario multifactor:

try {
  await _auth.signInWithEmailAndPassword(
    email: emailController.text,
    password: passwordController.text,
  );
} on FirebaseAuthMultiFactorException catch (e) {
  setState(() {
    error = '${e.message}';
  });
  final firstHint = e.resolver.hints.first;
  if (firstHint is! PhoneMultiFactorInfo) {
    return;
  }
  await FirebaseAuth.instance.verifyPhoneNumber(
    multiFactorSession: e.resolver.session,
    multiFactorInfo: firstHint,
    verificationCompleted: (_) {},
    verificationFailed: (_) {},
    codeSent: (String verificationId, int? resendToken) async {
      // See `firebase_auth` example app for a method of retrieving user's sms code: 
      // https://github.com/firebase/flutterfire/blob/master/packages/firebase_auth/firebase_auth/example/lib/auth.dart#L591
      final smsCode = await getSmsCodeFromUser(context);

      if (smsCode != null) {
        // Create a PhoneAuthCredential with the code
        final credential = PhoneAuthProvider.credential(
          verificationId: verificationId,
          smsCode: smsCode,
        );

        try {
          await e.resolver.resolveSignIn(
            PhoneMultiFactorGenerator.getAssertion(
              credential,
            ),
          );
        } on FirebaseAuthException catch (e) {
          print(e.message);
        }
      }
    },
    codeAutoRetrievalTimeout: (_) {},
  );
} catch (e) {
  ...
} 

¡Felicidades! Ingresó exitosamente a un usuario mediante la autenticación multifactor.

Que sigue