Ajoutez l'authentification multifacteur à votre application Flutter

Si vous avez effectué une mise à niveau vers l'authentification Firebase avec Identity Platform, vous pouvez ajouter l'authentification multifacteur SMS à votre application Flutter.

L'authentification multifacteur (MFA) augmente la sécurité de votre application. Même si les attaquants compromettent souvent les mots de passe et les comptes sociaux, il est plus difficile d’intercepter un message texte.

Avant que tu commences

  1. Activez au moins un fournisseur prenant en charge l’authentification multifacteur. Tous les fournisseurs prennent en charge MFA, à l'exception de l'authentification téléphonique, de l'authentification anonyme et d'Apple Game Center.

  2. Assurez-vous que votre application vérifie les e-mails des utilisateurs. MFA nécessite une vérification par e-mail. Cela empêche les acteurs malveillants de s'inscrire à un service avec une adresse e-mail qui ne leur appartient pas, puis de verrouiller le véritable propriétaire en ajoutant un deuxième facteur.

  3. Android : si vous n'avez pas déjà défini le hachage SHA-256 de votre application dans la console Firebase , faites-le. Consultez Authentification de votre client pour plus d’informations sur la recherche du 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 d'arrière-plan pour les notifications à distance. Pour afficher une explication détaillée de cette étape, consultez la documentation Firebase iOS Phone Auth .

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

Activation de l'authentification multifacteur

  1. Ouvrez la page Authentification > Méthode de connexion de la console Firebase.

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

    Vous devez également saisir les numéros de téléphone avec lesquels vous testerez votre application. Bien que facultatif, l’enregistrement des numéros de téléphone de test est fortement recommandé pour éviter toute limitation pendant le développement.

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

Choisir un modèle d'inscription

Vous pouvez choisir si votre application nécessite une authentification multifacteur, ainsi que comment et quand inscrire vos utilisateurs. Certains modèles courants incluent :

  • 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.

  • Offrez une option désactivable pour inscrire un deuxième facteur lors de l’inscription. Les applications qui souhaitent encourager, mais pas exiger, l’authentification multifacteur pourraient préférer cette approche.

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

  • Exiger l'ajout d'un deuxième facteur de manière incrémentielle lorsque l'utilisateur souhaite accéder à des fonctionnalités présentant des exigences de sécurité accrues.

Inscription d'un deuxième facteur

Pour inscrire un nouveau facteur secondaire pour un utilisateur :

  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. Vérifiez 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 vérifier le code :

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. Complétez l'inscription :

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

Le code ci-dessous montre un exemple complet d'inscription d'un deuxième 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: (_) {},
  );

Toutes nos félicitations! Vous avez enregistré avec succès un deuxième facteur d'authentification pour un utilisateur.

Connecter les utilisateurs avec un deuxième facteur

Pour connecter un utilisateur avec une vérification SMS à deux facteurs :

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

    Par exemple, si le premier facteur de l'utilisateur était un 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 a inscrit plusieurs facteurs secondaires, demandez-lui lequel utiliser :

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Envoyez un message de vérification au 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 terminer 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 montre 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) {
  ...
} 

Toutes nos félicitations! Vous avez réussi à connecter un utilisateur à l’aide de l’authentification multifacteur.

Et après