Dodawanie uwierzytelniania wielopoziomowego do aplikacji Flutter

Po przejściu na Uwierzytelnianie Firebase z Identity Platform możesz dodać uwierzytelnianie wielopoziomowe z użyciem SMS-ów w aplikacji Flutter.

Uwierzytelnianie wielopoziomowe (MFA) zwiększa bezpieczeństwo aplikacji. Osoby przeprowadzające atak często wykradają hasła i konta społecznościowe, przechwytywanie SMS-a jest co jest utrudnione.

Zanim zaczniesz

  1. Włącz co najmniej 1 dostawcę, który obsługuje uwierzytelnianie wielopoziomowe. Każdy dostawca obsługuje 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 adresu e-mail. Dzięki temu hakerzy nie będą mogli zarejestrować się w usłudze za pomocą adresu e-mail. których nie należy, a następnie zablokować rzeczywistego właściciela, dodając współczynnik konwersji.

  3. Android: jeśli nie masz jeszcze ustawionego skrótu SHA-256 aplikacji w w konsoli Firebase. Przeczytaj artykuł Uwierzytelnianie klienta. .

  4. iOS: w Xcode włącz powiadomienia push dla swojego projektu i upewnij się Twój klucz uwierzytelniania APNs jest skonfigurowany za pomocą Komunikacji w chmurze Firebase (FCM). Dodatkowo musisz: włącz tryby działania w tle na potrzeby zdalnych powiadomień. Szczegółowy opis tego kroku znajdziesz w dokumentacji uwierzytelniania telefonu na urządzeniach z iOS w Firebase.

  5. Internet: upewnij się, że w konsoli Firebase została dodana domena aplikacji w sekcji Domeny przekierowywania OAuth

Włączanie uwierzytelniania wielopoziomowego

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

  2. W sekcji Zaawansowane włącz Uwierzytelnianie wielopoziomowe przez SMS-y.

    Wpisz też numery telefonów, które będą używane podczas testowania aplikacji. Chociaż jest to opcjonalne, zdecydowanie zalecamy zarejestrowanie testowych numerów telefonów, i uniknąć ograniczenia w trakcie programowania.

  3. Jeśli domena aplikacji nie została jeszcze autoryzowana, dodaj ją do zezwolenia na liście Uwierzytelnianie > Ustawienia w konsoli Firebase.

Wybór wzorca rejestracji

Możesz zdecydować, czy Twoja aplikacja wymaga uwierzytelniania wielopoziomowego i w jaki sposób i kiedy zarejestrować użytkowników. Oto kilka często spotykanych wzorców:

  • Zarejestruj drugi składnik logowania użytkownika w ramach rejestracji. Użyj tej , jeśli Twoja aplikacja wymaga uwierzytelniania wielopoziomowego dla wszystkich użytkowników.

  • Zaoferuj możliwą do pominięcia opcję rejestracji drugiego składnika podczas rejestracji. aplikacji; które chcą zachęcić do uwierzytelniania wielopoziomowego, ale nie wymagają tego, mogą preferować tę metodę.

  • umożliwia dodanie drugiego składnika z konta lub profilu użytkownika. na stronie zarządzania, a nie na ekranie rejestracji. Pozwala to zminimalizować tarcie podczas rejestracji, a jednocześnie stosować uwierzytelnianie dwuskładnikowe. dostępna dla użytkowników, którzy zwracają uwagę na bezpieczeństwo.

  • Wymagaj stopniowego dodawania drugiego składnika, gdy użytkownik chce uzyskać dostęp funkcje o wyższych wymaganiach w zakresie bezpieczeństwa.

Rejestrowanie drugiego składnika

Aby zarejestrować nowy czynnik dodatkowy dla użytkownika:

  1. Ponownie uwierzytelnij użytkownika.

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

  3. Pobierz sesję wielopoziomową dla użytkownika:

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. Zweryfikuj numer telefonu za pomocą sesji wielopoziomowej i oddzwaniań:

    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. Gdy zostanie wysłany SMS, poproś użytkownika o jego potwierdzenie:

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

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

Poniżej znajdziesz pełny przykład rejestrowania drugiego składnika:

  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! Udało Ci się zarejestrować drugi etap uwierzytelniania dla użytkownika.

Logowanie użytkowników przy użyciu drugiego składnika

Aby zalogować użytkownika za pomocą weryfikacji dwuetapowej przez SMS:

  1. Zaloguj użytkownika na podstawie pierwszego składnika, a potem przechwyć FirebaseAuthMultiFactorException wyjątek. Ten błąd zawiera programu do rozpoznawania nazw, za pomocą którego można uzyskać zarejestrowane drugie czynniki użytkownika. Zawiera też powiązaną sesję, która potwierdza, że użytkownik został zweryfikowany. uwierzytelniono za pomocą pierwszego składnika.

    Jeśli np. pierwszym czynnikiem były adres e-mail i hasło użytkownika:

    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 kilka czynników dodatkowych, zapytaj go, który do użycia:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Wyślij na telefon użytkownika wiadomość weryfikacyjną ze wskazówką i sesja wielopoziomowa:

    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żej znajdziesz pełny przykład logowania użytkownika wielopoziomowego:

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! Udało Ci się zalogować użytkownika za pomocą uwierzytelniania wielopoziomowego uwierzytelnianie.

Co dalej?