Dodaj uwierzytelnianie wieloskładnikowe do swojej aplikacji Flutter

Jeśli zaktualizowałeś uwierzytelnianie Firebase z platformą tożsamości, możesz dodać wieloskładnikowe uwierzytelnianie SMS do swojej aplikacji Flutter.

Uwierzytelnianie wieloskładnikowe (MFA) zwiększa bezpieczeństwo Twojej aplikacji. Chociaż napastnicy często naruszają hasła i konta społecznościowe, przechwycenie wiadomości tekstowej jest trudniejsze.

Zanim zaczniesz

  1. Włącz co najmniej jednego dostawcę obsługującego uwierzytelnianie wieloskładnikowe. Każdy dostawca obsługuje usługę MFA, z wyjątkiem uwierzytelniania telefonicznego, uwierzytelniania anonimowego i Apple Game Center.

  2. Upewnij się, że Twoja aplikacja weryfikuje adresy e-mail użytkowników. MFA wymaga weryfikacji e-mailowej. Zapobiega to rejestrowaniu się złośliwych aktorów w usłudze przy użyciu adresu e-mail, którego nie należą, a następnie blokowaniu prawdziwego właściciela poprzez dodanie drugiego czynnika.

  3. Android : jeśli nie ustawiłeś jeszcze skrótu SHA-256 swojej aplikacji w konsoli Firebase , zrób to. Aby uzyskać informacje na temat znajdowania skrótu SHA-256 aplikacji, zobacz Uwierzytelnianie klienta .

  4. iOS : w Xcode włącz powiadomienia push dla swojego projektu i upewnij się, że klucz uwierzytelniania APN jest skonfigurowany za pomocą Firebase Cloud Messaging (FCM) . Dodatkowo należy włączyć tryby tła dla powiadomień zdalnych. Aby zapoznać się ze szczegółowym wyjaśnieniem tego kroku, zapoznaj się z dokumentacją Firebase iOS Phone Auth .

  5. Sieć : Upewnij się, że dodałeś domenę aplikacji w konsoli Firebase , w obszarze domeny przekierowań OAuth .

Włączanie uwierzytelniania wieloskładnikowego

  1. Otwórz stronę Uwierzytelnianie > Metoda logowania w konsoli Firebase.

  2. W sekcji Zaawansowane włącz uwierzytelnianie wieloskładnikowe SMS .

    Powinieneś także wpisać numery telefonów, z którymi będziesz testować aplikację. Chociaż jest to opcjonalne, zdecydowanie zaleca się rejestrowanie testowych numerów telefonów, aby uniknąć ograniczania przepustowości podczas programowania.

  3. Jeśli nie autoryzowałeś jeszcze domeny swojej aplikacji, dodaj ją do listy dozwolonych na stronie Uwierzytelnianie > Ustawienia w konsoli Firebase.

Wybór wzoru zapisu

Możesz wybrać, czy Twoja aplikacja wymaga uwierzytelniania wieloskładnikowego oraz jak i kiedy rejestrować użytkowników. Niektóre typowe wzorce obejmują:

  • Zarejestruj drugi czynnik użytkownika w ramach rejestracji. Użyj tej metody, jeśli aplikacja wymaga uwierzytelniania wieloskładnikowego dla wszystkich użytkowników.

  • Zaoferuj możliwość pominięcia opcji zapisania drugiego czynnika podczas rejestracji. Aplikacje, które chcą zachęcać do uwierzytelniania wieloskładnikowego, ale go nie wymagają, mogą preferować to podejście.

  • Zapewnij możliwość dodania drugiego elementu ze strony zarządzania kontem lub profilem użytkownika zamiast ekranu rejestracji. Minimalizuje to problemy podczas procesu rejestracji, jednocześnie udostępniając uwierzytelnianie wieloskładnikowe użytkownikom wrażliwym na bezpieczeństwo.

  • Wymagaj stopniowego dodawania drugiego czynnika, gdy użytkownik chce uzyskać dostęp do funkcji o podwyższonych wymaganiach bezpieczeństwa.

Rejestracja drugiego czynnika

Aby zapisać nowy dodatkowy czynnik dla użytkownika:

  1. Ponownie uwierzytelnij użytkownika.

  2. Poproś użytkownika o podanie numeru telefonu.

  3. Uzyskaj sesję wieloczynnikową dla użytkownika:

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. Zweryfikuj numer telefonu za pomocą sesji wieloczynnikowej i połączeń zwrotnych:

    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. Po wysłaniu kodu SMS poproś użytkownika o weryfikację kodu:

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. Dokończ rejestrację:

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

Poniższy kod przedstawia pełny przykład rejestracji drugiego czynnika:

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

Gratulacje! Pomyślnie zarejestrowałeś drugi czynnik uwierzytelniający dla użytkownika.

Logowanie użytkowników przy użyciu drugiego czynnika

Aby zalogować użytkownika za pomocą dwuskładnikowej weryfikacji SMS:

  1. Zaloguj użytkownika przy użyciu pierwszego czynnika, a następnie przechwyć wyjątek FirebaseAuthMultiFactorException . Ten błąd zawiera moduł rozpoznawania nazw, którego można użyć w celu uzyskania zarejestrowanych przez użytkownika współczynników drugich. Zawiera także podstawową sesję potwierdzającą, że użytkownik pomyślnie uwierzytelnił się za pomocą pierwszego czynnika.

    Na przykład, jeśli pierwszym czynnikiem użytkownika był adres e-mail i hasło:

    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. Jeśli użytkownik ma zarejestrowanych wiele dodatkowych czynników, zapytaj go, którego z nich użyć:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Wyślij wiadomość weryfikacyjną na telefon użytkownika z podpowiedzią i sesją wieloczynnikową:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. Wywołaj resolver.resolveSignIn() aby ukończyć dodatkowe uwierzytelnianie:

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

Poniższy kod przedstawia pełny przykład logowania użytkownika wieloskładnikowego:

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

Gratulacje! Pomyślnie zalogowałeś użytkownika przy użyciu uwierzytelniania wieloskładnikowego.

Co dalej