Menambahkan autentikasi multi-faktor ke aplikasi Flutter

Jika telah mengupgrade ke Firebase Authentication dengan Identity Platform, Anda dapat menambahkan autentikasi multi-faktor SMS ke aplikasi Flutter.

Autentikasi multi-faktor (MFA) meningkatkan keamanan aplikasi Anda. Meskipun penyerang sering membobol sandi dan akun media sosial, menyadap pesan teks lebih sulit dilakukan.

Sebelum memulai

  1. Aktifkan minimal satu penyedia yang mendukung autentikasi multi-faktor. Setiap penyedia mendukung MFA, kecuali autentikasi dengan ponsel, autentikasi anonim, dan Apple Game Center.

  2. Pastikan aplikasi Anda memverifikasi email pengguna. MFA memerlukan verifikasi email. Tindakan ini mencegah pelaku kejahatan mendaftar ke layanan dengan email yang bukan miliknya, lalu mengunci pemilik sebenarnya dari akunnya dengan menambahkan faktor kedua.

  3. Android: Setel hash SHA-256 aplikasi Anda di Firebase console jika belum melakukannya. Baca Mengautentikasi Klien untuk mengetahui informasi tentang cara menemukan hash SHA-256 aplikasi.

  4. iOS: Di Xcode, aktifkan notifikasi push untuk project Anda & pastikan kunci autentikasi APNs Anda dikonfigurasi dengan Firebase Cloud Messaging (FCM). Untuk melihat penjelasan mendalam tentang langkah ini, lihat dokumentasi Autentikasi Ponsel iOS Firebase.

  5. Web: Pastikan Anda telah menambahkan domain aplikasi di Firebase console di bagian OAuth redirect domains.

Mengaktifkan autentikasi multi-faktor

  1. Buka halaman Authentication > Sign-in method di Firebase console.

  2. Di bagian Advanced, aktifkan SMS Multi-factor Authentication.

    Anda juga harus memasukkan nomor telepon yang akan digunakan untuk menguji aplikasi. Meskipun opsional, mendaftarkan nomor telepon pengujian sangat direkomendasikan untuk menghindari throttling selama tahap pengembangan.

  3. Jika Anda belum memberikan otorisasi pada domain aplikasi, tambahkan domain tersebut ke daftar yang diizinkan di halaman Authentication > Settings di Firebase console.

Memilih pola pendaftaran

Anda dapat memilih apakah aplikasi memerlukan autentikasi multi-faktor atau tidak, serta cara dan waktu untuk mendaftarkan pengguna. Beberapa pola yang umum antara lain:

  • Mendaftarkan faktor kedua pengguna sebagai bagian dari pendaftaran. Gunakan metode ini jika aplikasi Anda memerlukan autentikasi multi-faktor untuk semua pengguna.

  • Menawarkan opsi yang dapat dilewati untuk mendaftarkan faktor kedua selama pendaftaran. Aplikasi yang ingin mendukung, tetapi tidak memerlukan, autentikasi multi-faktor dapat memilih pendekatan ini.

  • Memungkinkan untuk menambahkan faktor kedua dari halaman pengelolaan akun atau profil pengguna, bukan dari layar pendaftaran. Hal ini akan meminimalkan hambatan selama proses pendaftaran, sekaligus tetap menyediakan autentikasi multi-faktor untuk pengguna yang rentan terhadap ancaman keamanan.

  • Memerlukan penambahan faktor kedua secara inkremental saat pengguna ingin mengakses fitur dengan persyaratan keamanan yang ditingkatkan.

Mendaftarkan faktor kedua

Untuk mendaftarkan faktor sekunder baru untuk pengguna:

  1. Autentikasi ulang pengguna.

  2. Minta pengguna untuk memasukkan nomor teleponnya.

  3. Dapatkan sesi multi-faktor untuk pengguna:

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. Verifikasikan nomor telepon dengan sesi multi-faktor dan callback Anda:

    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. Setelah kode SMS dikirim, minta pengguna untuk memverifikasi kode tersebut:

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. Selesaikan pendaftaran:

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

Kode di bawah menunjukkan contoh lengkap proses pendaftaran faktor kedua:

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

Selamat! Anda berhasil mendaftarkan faktor autentikasi kedua untuk pengguna.

Memproses login pengguna dengan faktor kedua

Untuk memproses login pengguna dengan verifikasi SMS dua faktor:

  1. Proses login pengguna dengan faktor pertamanya, lalu tangkap pengecualian FirebaseAuthMultiFactorException. Error ini berisi resolver, yang dapat Anda gunakan untuk mendapatkan faktor kedua yang didaftarkan pengguna. Error ini juga berisi sesi yang mendasarinya yang membuktikan bahwa pengguna berhasil diautentikasi dengan faktor pertamanya.

    Misalnya, jika faktor pertama pengguna adalah email dan sandi:

    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. Jika pengguna mendaftarkan beberapa faktor sekunder, tanyakan kepada mereka faktor mana yang ingin digunakan:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Kirim pesan verifikasi ke ponsel pengguna dengan petunjuk dan sesi multi-faktor:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. Panggil resolver.resolveSignIn() untuk menyelesaikan autentikasi sekunder:

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

Kode di bawah menunjukkan contoh lengkap proses login pengguna multi-faktor:

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

Selamat! Anda berhasil memproses login pengguna menggunakan autentikasi multi-faktor.

Langkah berikutnya