Aggiungi l'autenticazione a più fattori alla tua app Flutter

Se hai eseguito l'upgrade all'autenticazione Firebase con Identity Platform, puoi aggiungere l'autenticazione a più fattori tramite SMS alla tua app Flutter.

L'autenticazione a più fattori (MFA) aumenta la sicurezza della tua app. Sebbene gli aggressori spesso compromettano password e account social, intercettare un messaggio di testo è più difficile.

Prima di iniziare

  1. Abilita almeno un provider che supporti l'autenticazione a più fattori. Tutti i provider supportano MFA, ad eccezione dell'autenticazione telefonica, dell'autenticazione anonima e di Apple Game Center.

  2. Assicurati che la tua app stia verificando le email degli utenti. L'AMF richiede la verifica dell'e-mail. Ciò impedisce agli autori malintenzionati di registrarsi a un servizio con un indirizzo email di cui non sono i proprietari e quindi di escludere il vero proprietario aggiungendo un secondo fattore.

  3. Android : se non hai già impostato l'hash SHA-256 della tua app nella console Firebase , fallo. Consulta Autenticazione del client per informazioni su come trovare l'hash SHA-256 della tua app.

  4. iOS : in Xcode, abilita le notifiche push per il tuo progetto e assicurati che la chiave di autenticazione APN sia configurata con Firebase Cloud Messaging (FCM) . Inoltre, è necessario abilitare le modalità in background per le notifiche remote. Per visualizzare una spiegazione approfondita di questo passaggio, consulta la documentazione relativa all'autenticazione del telefono iOS di Firebase .

  5. Web : assicurati di aver aggiunto il dominio delle applicazioni sulla console Firebase , in Domini di reindirizzamento OAuth .

Abilitazione dell'autenticazione a più fattori

  1. Apri la pagina Autenticazione > Metodo di accesso della console Firebase.

  2. Nella sezione Avanzate , abilita l'autenticazione a più fattori SMS .

    Dovresti anche inserire i numeri di telefono con cui testerai la tua app. Anche se facoltativa, la registrazione dei numeri di telefono di prova è fortemente consigliata per evitare limitazioni durante lo sviluppo.

  3. Se non hai già autorizzato il dominio della tua app, aggiungilo all'elenco di autorizzazioni nella pagina Autenticazione > Impostazioni della console Firebase.

Scegliere un modello di iscrizione

Puoi scegliere se la tua app richiede l'autenticazione a più fattori e come e quando registrare i tuoi utenti. Alcuni modelli comuni includono:

  • Registra il secondo fattore dell'utente come parte della registrazione. Utilizza questo metodo se la tua app richiede l'autenticazione a più fattori per tutti gli utenti.

  • Offri un'opzione ignorabile per iscrivere un secondo fattore durante la registrazione. Le app che vogliono incoraggiare, ma non richiedere, l'autenticazione a più fattori potrebbero preferire questo approccio.

  • Fornire la possibilità di aggiungere un secondo fattore dall'account dell'utente o dalla pagina di gestione del profilo, anziché dalla schermata di registrazione. Ciò riduce al minimo gli attriti durante il processo di registrazione, pur rendendo disponibile l’autenticazione a più fattori per gli utenti sensibili alla sicurezza.

  • Richiedere l'aggiunta incrementale di un secondo fattore quando l'utente desidera accedere a funzionalità con requisiti di sicurezza maggiori.

Iscrizione di un secondo fattore

Per registrare un nuovo fattore secondario per un utente:

  1. Riautenticare l'utente.

  2. Chiedi all'utente di inserire il proprio numero di telefono.

  3. Ottieni una sessione a più fattori per l'utente:

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. Verifica il numero di telefono con una sessione multifattore e le tue richiamate:

    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 volta inviato il codice SMS, chiedi all'utente di verificare il codice:

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. Completa l'iscrizione:

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

Il codice seguente mostra un esempio completo di iscrizione di un secondo fattore:

  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: (_) {},
  );

Congratulazioni! Hai registrato correttamente un secondo fattore di autenticazione per un utente.

Accesso degli utenti con un secondo fattore

Per accedere a un utente con la verifica SMS a due fattori:

  1. Accedi all'utente con il primo fattore, quindi rileva l'eccezione FirebaseAuthMultiFactorException . Questo errore contiene un risolutore che puoi utilizzare per ottenere i secondi fattori registrati dell'utente. Contiene anche una sessione sottostante che dimostra che l'utente si è autenticato correttamente con il primo fattore.

    Ad esempio, se il primo fattore dell'utente era un indirizzo email e una password:

    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. Se l'utente ha registrato più fattori secondari, chiedigli quale utilizzare:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Invia un messaggio di verifica al telefono dell'utente con il suggerimento e la sessione a più fattori:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. Chiamaresolver.resolveSignIn resolver.resolveSignIn() per completare l'autenticazione secondaria:

    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);
      }
    }
    

Il codice seguente mostra un esempio completo di accesso di un utente a più fattori:

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

Congratulazioni! Hai eseguito correttamente l'accesso di un utente utilizzando l'autenticazione a più fattori.

Qual è il prossimo