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

Nếu đã nâng cấp lên Firebase Authentication bằng Identity Platform, bạn có thể thêm tính năng xác thực đa yếu tố bằng SMS vào ứng dụng Flutter.

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

Trước khi bắt đầu

  1. Bật ít nhất một nhà cung cấp hỗ trợ tính năng 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 bằng đ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 của người dùng. MFA yêu cầu xác minh email. Điều này ngăn chặn các đối tượng xấu đăng ký một dịch vụ bằng email mà họ không sở hữu, sau đó chặn chủ sở hữu thực sự bằng cách thêm một 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 đặt hàm băm đó. Hãy xem phần Xác thực ứng dụng khách để biết thông tin về cách tìm hàm băm SHA-256 của ứng dụng.

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

  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 của Firebase, trong mục Miền chuyển hướng OAuth.

Bật tính năng 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 của Firebase.

  2. Trong phần Nâng cao, hãy bật chế độ 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 để kiểm thử ứng dụng. Mặc dù không bắt buộc, nhưng bạn nên đăng ký số điện thoại kiểm thử để tránh bị điều tiết trong quá trình phát triển.

  3. Nếu bạn chưa uỷ quyền cho miền của ứng dụng, 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.

Chọn một mẫu đăng ký

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 trong quá trình đăng ký. Sử dụng phương thức 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 lựa chọn có thể bỏ qua để đăng ký yếu tố thứ hai trong quá trình đăng ký. Những ứ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ể ưu tiên phương pháp này.

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

  • Yêu cầu tăng dần việc thêm yếu tố thứ hai khi người dùng muốn truy cập vào 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

Cách đă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.

  3. Lấy một phiên có nhiều 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 một phiên nhiều yếu tố và các lệnh 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 quy trình đăng ký:

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

Đoạn mã dưới đây cho thấy 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/main/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: (_) {},
  );

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

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

Cách đăng nhập người dùng bằng tính năng xác minh qua SMS hai yếu tố:

  1. Đăng nhập cho người dùng bằng yếu tố đầu tiên của họ, sau đó bắt ngoại lệ FirebaseAuthMultiFactorException. Lỗi này chứa một trình phân giải mà bạn có thể 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 rằng người dùng đã xác thực thành công bằng yếu tố đầu tiên.

    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ọ muốn sử dụng yếu tố nào:

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

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

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

Đoạn mã dưới đây cho thấy một ví dụ hoàn chỉnh về việc đăng nhập cho người dùng có nhiều 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/main/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) {
  ...
}

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

Bước tiếp theo