Thêm xác thực đa yếu tố vào ứng dụng Flutter của bạn

Nếu đã nâng cấp lên Xác thực Firebase với Nền tảng nhận dạng, bạn có thể thêm xác thực đa yếu tố SMS vào ứng dụng Flutter của mình.

Xác thực đa yếu tố (MFA) tăng tính bảo mật cho ứng dụng của bạn. Trong khi những kẻ tấn công thường xâm phạm mật khẩu và tài khoản mạng xã hội thì việc chặn tin nhắn văn bản lại khó khăn hơn.

Trước khi bắt đầu

  1. Kích hoạt ít nhất một nhà cung cấp hỗ trợ xác thực đa yếu tố. Mọi nhà cung cấp đều hỗ trợ MFA, ngoại trừ xác thực qua điện thoại, xác thực ẩn danh và Apple Game Center.

  2. Đảm bảo ứng dụng của bạn đang xác minh email người dùng. MFA yêu cầu xác minh email. Điều này ngăn các tác nhân độc hại đăng ký dịch vụ bằng email mà họ không sở hữu, sau đó khóa chủ sở hữu thực sự bằng cách thêm yếu tố thứ hai.

  3. Android : Nếu bạn chưa đặt hàm băm SHA-256 của ứng dụng trong bảng điều khiển Firebase , hãy làm như vậy. Xem Xác thực ứng dụng khách của bạn để biết thông tin về cách tìm hàm băm SHA-256 của ứng dụng của bạn.

  4. iOS : Trong Xcode, hãy bật thông báo đẩy cho dự án của bạn và đảm bảo khóa xác thực APN của bạn được định cấu hình với Nhắn tin qua đám mây Firebase (FCM) . Ngoài ra, bạn phải bật chế độ nền cho thông báo từ xa. Để xem giải thích chi tiết về bước này, hãy xem tài liệu Xác thực điện thoại iOS của Firebase .

  5. Web : Đảm bảo rằng bạn đã thêm miền ứng dụng của mình trên bảng điều khiển Firebase , trong miền chuyển hướng OAuth .

Kích hoạt xác thực đa yếu tố

  1. Mở trang Xác thực > Phương thức đăng nhập của bảng điều khiển Firebase.

  2. Trong phần Nâng cao , bật Xác thực đa yếu tố qua SMS .

    Bạn cũng nên nhập số điện thoại mà bạn sẽ dùng để thử nghiệm ứng dụng của mình. Mặc dù là tùy chọn nhưng bạn nên đăng ký số điện thoại thử nghiệm để tránh bị hạn chế trong quá trình phát triển.

  3. Nếu bạn chưa ủy quyền miền ứng dụng của mình, hãy thêm miền đó vào danh sách cho phép trên trang Xác thực > Cài đặt của bảng điều khiển Firebase.

Lựa chọn hình thức tuyển sinh

Bạn có thể chọn xem ứng dụng của mình có yêu cầu xác thực đa yếu tố hay không cũng như cách thức và thời điểm đăng ký người dùng. Một số mẫu phổ biến bao gồm:

  • Đăng ký yếu tố thứ hai của người dùng như một phần của quá trình đăng ký. Sử dụng phương pháp này nếu ứng dụng của bạn yêu cầu xác thực đa yếu tố cho tất cả người dùng.

  • Cung cấp tùy chọn có thể bỏ qua để đăng ký yếu tố thứ hai trong quá trình đăng ký. Các ứng dụng muốn khuyến khích nhưng không yêu cầu xác thực đa yếu tố có thể thích phương pháp này.

  • Cung cấp khả năng thêm yếu tố thứ hai từ trang quản lý hồ sơ hoặc tài khoản của người dùng, thay vì màn hình đăng ký. Điều này giảm thiểu xung đột trong quá trình đăng ký, trong khi vẫn cung cấp xác thực đa yếu tố cho người dùng nhạy cảm về bảo mật.

  • Yêu cầu tăng dần yếu tố thứ hai khi người dùng muốn truy cập các tính năng có yêu cầu bảo mật cao hơn.

Đăng ký yếu tố thứ hai

Để đăng ký một yếu tố phụ mới cho người dùng:

  1. Xác thực lại người dùng.

  2. Yêu cầu người dùng nhập số điện thoại của họ.

  3. Nhận phiên đa yếu tố cho người dùng:

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. Xác minh số điện thoại bằng phiên đa yếu tố và cuộc gọi lại của bạn:

    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. Sau khi mã SMS được gửi, hãy yêu cầu người dùng xác minh mã:

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. Hoàn tất việc đăng ký:

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

Mã bên dưới hiển thị một ví dụ hoàn chỉnh về việc đăng ký yếu tố thứ hai:

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

Chúc mừng! Bạn đã đăng ký thành công yếu tố xác thực thứ hai cho người dùng.

Đăng nhập người dùng bằng yếu tố thứ hai

Để đăng nhập người dùng bằng xác minh SMS hai yếu tố:

  1. Đăng nhập người dùng bằng yếu tố đầu tiên của họ, sau đó nắm bắt ngoại lệ FirebaseAuthMultiFactorException . Lỗi này chứa một trình giải quyết mà bạn có thể sử dụng để lấy các yếu tố thứ hai đã đăng ký của người dùng. Nó cũng chứa một phiên cơ bản chứng minh người dùng đã xác thực thành công bằng yếu tố đầu tiên của họ.

    Ví dụ: nếu yếu tố đầu tiên của người dùng là email và mật khẩu:

    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. Nếu người dùng đã đăng ký nhiều yếu tố phụ, hãy hỏi họ nên sử dụng yếu tố nào:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. Gửi tin nhắn xác minh đến điện thoại của người dùng kèm theo phiên gợi ý và đa yếu tố:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. Gọi resolver.resolveSignIn() để hoàn tất xác thực phụ:

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

Mã bên dưới hiển thị một ví dụ hoàn chỉnh về việc đăng nhập người dùng đa yếu tố:

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

Chúc mừng! Bạn đã đăng nhập thành công người dùng bằng xác thực đa yếu tố.

Cái gì tiếp theo