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 tính năng Xác thực Firebase bằng Nền tảng nhận dạng, bạn có thể thêm tính năng xác thực đa yếu tố qua SMS vào ứng dụng Flutter của mình.

Tính năng xác thực đa yếu tố (MFA) giúp tăng cường độ bảo mật cho ứng dụng của bạn. Trong khi 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, nên việc chặn tin nhắn văn bản là khó hơn.

Trước khi bắt đầu

  1. Bậ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ợ tính năng MFA, ngoại trừ tính năng xác thực qua điện thoại, xác thực ẩn danh và Trung tâm trò chơi của Apple.

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

  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 của Firebase. Xem bài viết Xác thực ứng dụng để 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 APN của bạn đượ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 về Xác thực điện thoại trên 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 của Firebase, trong 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, bật Xác thực đa yếu tố SMS.

    Bạn cũng nên nhập số điện thoại dùng để thử nghiệm ứ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 thử nghiệm để tránh việc điều tiết trong quá trình phát triển.

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

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

Bạn có thể chọn xem ứng dụng của bạn có cần xác thực đa yếu tố hay không, cũng như 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 bản thảo này nếu ứng dụng của bạn yêu cầu xác thực đa yếu tố đối với 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ý. Chiến dịch Quảng cáo ứng dụng muốn khuyến khích nhưng không bắt buộc, xác thực đa yếu tố có thể thích phương pháp này hơn.

  • Cho phép thêm yếu tố thứ hai từ tài khoản hoặc hồ sơ của người dùng thay vì màn hình đăng ký. Việc này giúp giảm thiểu rào cản trong quá trình đăng ký, trong khi vẫn thực hiện xác thực đa yếu tố dành cho những người dùng nhạy cảm về bảo mật.

  • Yêu cầu thêm dần yếu tố thứ hai khi người dùng muốn truy cập 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 của họ.

  3. Nhận một 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 qua một phiên đa 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 gửi mã qua SMS, 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 là ví dụ hoàn chỉnh về cách đă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: (_) {},
  );

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 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 hai yếu tố qua SMS:

  1. Đăng nhập cho người dùng bằng yếu tố đầu tiên, sau đó nắm bắt FirebaseAuthMultiFactorException ngoại lệ. Lỗi này có chứa Trình phân giải mà bạn có thể sử dụng để lấy yếu tố thứ hai đã đăng ký của người dùng. Dữ liệu này cũng chứa một phiên cơ bản chứng minh người dùng thành công xác thực với 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ọ xem yếu tố nào để sử dụng:

    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 gợi ý và phiên đ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);
      }
    }
    

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

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

Bước tiếp theo