Ajouter l'authentification multifacteur à votre application Flutter

Si vous êtes passé à Firebase Authentication avec Identity Platform, vous pouvez ajouter l'authentification multifacteur par SMS à votre application Flutter.

L'authentification multifacteur (MFA) renforce la sécurité de votre application. Bien que les pirates informatiques compromettent souvent les mots de passe et les comptes de réseaux sociaux, il est plus difficile d'intercepter un SMS.

Avant de commencer

  1. Activez au moins un fournisseur compatible avec l'authentification multifacteur. Tous les fournisseurs acceptent l'authentification multifacteur, sauf l'authentification par téléphone, l'authentification anonyme et Apple Game Center.

  2. Assurez-vous que votre application valide les adresses e-mail des utilisateurs. L'authentification multifacteur nécessite une validation de l'adresse e-mail. Cela empêche les utilisateurs malveillants de s'enregistrer à un service avec une adresse e-mail dont ils ne sont pas propriétaire, puis de bloquer le propriétaire réel en ajoutant un second facteur.

  3. Android : si vous n'avez pas encore défini le hachage SHA-256 de votre application dans la console Firebase, faites-le. Consultez Authentifier votre client pour savoir comment trouver le hachage SHA-256 de votre application.

  4. iOS : dans Xcode, activez les notifications push pour votre projet et assurez-vous que votre clé d'authentification APN est configurée avec Firebase Cloud Messaging (FCM). De plus, vous devez activer les modes en arrière-plan pour les notifications à distance. Pour une explication détaillée de cette étape, consultez la documentation sur Firebase iOS Phone Auth.

  5. Web : assurez-vous d'avoir ajouté le domaine de votre application dans la console Firebase, sous Domaines de redirection OAuth.

Activer l'authentification multifacteur

  1. Ouvrez la page Authentication > Sign-in method (Authentification > Mode de connexion) de la console Firebase.

  2. Dans la section Avancé, activez l'authentification multifacteur par SMS.

    Vous devez également saisir les numéros de téléphone avec lesquels vous souhaitez tester votre application. Bien que cette étape soit facultative, il est fortement recommandé d'enregistrer des numéros de téléphone de test pour éviter toute limitation lors du développement.

  3. Si vous n'avez pas encore autorisé le domaine de votre application, ajoutez-le à la liste d'autorisations sur la page Authentication > Settings (Authentification > Paramètres) de la console Firebase.

Choisir un modèle d'inscription

Vous pouvez décider si votre application nécessite une authentification multifacteur, et comment et quand inscrire vos utilisateurs. Voici quelques modèles courants :

  • Inscrivez le deuxième facteur de l'utilisateur dans le cadre de l'inscription. Utilisez cette méthode si votre application nécessite une authentification multifacteur pour tous les utilisateurs.

  • Proposez une option désactivable pour inscrire un second facteur lors de l'enregistrement. Les applications qui souhaitent encourager mais pas exiger l'authentification multifacteur peuvent préférer cette approche.

  • Offrez la possibilité d'ajouter un second facteur à partir de la page de gestion de compte ou de profil de l'utilisateur, au lieu de l'écran d'inscription. Cela minimise les frictions lors du processus d'enregistrement tout en rendant encore l'authentification multifacteur disponible pour les utilisateurs sensibles à la sécurité.

  • Exigez l'ajout incrémentiel d'un second facteur lorsque l'utilisateur souhaite accéder aux fonctionnalités présentant des exigences de sécurité accrues.

Inscrire un second facteur

Pour inscrire un nouveau facteur secondaire pour un utilisateur, procédez comme suit :

  1. Réauthentifiez l'utilisateur.

  2. Demandez à l'utilisateur de saisir son numéro de téléphone.

  3. Obtenez une session multifacteur pour l'utilisateur :

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. Validez le numéro de téléphone avec une session multifacteur et vos rappels :

    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. Une fois le code SMS envoyé, demandez à l'utilisateur de le vérifier :

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. Terminez l'enregistrement:

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

Le code ci-dessous montre un exemple complet d'inscription d'un second facteur :

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

Félicitations ! Vous avez enregistré un second facteur d'authentification pour un utilisateur.

Connecter des utilisateurs avec un second facteur

Pour connecter un utilisateur via la validation SMS à deux facteurs, procédez comme suit :

  1. Connectez l'utilisateur avec son premier facteur, puis détectez l'exception FirebaseAuthMultiFactorException. Cette erreur contient un résolveur, que vous pouvez utiliser pour obtenir les seconds facteurs inscrits de l'utilisateur. Elle contient également une session sous-jacente attestant que l'utilisateur s'est authentifié avec succès avec son premier facteur.

    Par exemple, si le premier facteur de l'utilisateur est une adresse e-mail et un mot de passe :

    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 l'utilisateur possède plusieurs facteurs secondaires inscrits, demandez-lui lequel utiliser :

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Envoyez un message de validation sur le téléphone de l'utilisateur avec l'indice et la session multifacteur :

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. Appelez resolver.resolveSignIn() pour effectuer l'authentification secondaire :

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

Le code ci-dessous illustre un exemple complet de connexion d'un utilisateur multifacteur :

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

Félicitations ! Vous avez connecté un utilisateur à l'aide de l'authentification multifacteur.

Étape suivante