เพิ่มการรับรองความถูกต้องแบบหลายปัจจัยให้กับแอป Flutter ของคุณ

หากคุณอัปเกรดเป็น Firebase Authentication ด้วย Identity Platform แล้ว คุณสามารถเพิ่ม SMS Multi-Factor Authentication ให้กับแอป Flutter ของคุณได้

การตรวจสอบสิทธิ์แบบหลายปัจจัย (MFA) ช่วยเพิ่มความปลอดภัยให้กับแอปของคุณ แม้ว่าผู้โจมตีมักจะบุกรุกรหัสผ่านและบัญชีโซเชียล แต่การสกัดกั้นข้อความนั้นยากกว่า

ก่อนที่คุณจะเริ่ม

  1. เปิดใช้งานผู้ให้บริการอย่างน้อยหนึ่งรายที่รองรับการรับรองความถูกต้องแบบหลายปัจจัย ผู้ให้บริการทุกรายรองรับ MFA ยกเว้น การตรวจสอบสิทธิ์ทางโทรศัพท์ การตรวจสอบแบบไม่เปิดเผยตัวตน และ Apple Game Center

  2. ตรวจสอบให้แน่ใจว่าแอปของคุณกำลังยืนยันอีเมลของผู้ใช้ MFA กำหนดให้มีการยืนยันอีเมล วิธีนี้จะป้องกันไม่ให้ผู้ไม่ประสงค์ดีลงทะเบียนใช้บริการด้วยอีเมลที่พวกเขาไม่ได้เป็นเจ้าของ จากนั้นจึงล็อกเจ้าของที่แท้จริงออกด้วยการเพิ่มปัจจัยที่สอง

  3. Android : หากคุณยังไม่ได้ตั้งค่าแฮช SHA-256 ของแอปใน คอนโซล Firebase ให้ดำเนินการดังกล่าว ดู การตรวจสอบสิทธิ์ไคลเอ็นต์ของคุณ สำหรับข้อมูลเกี่ยวกับการค้นหาแฮช SHA-256 ของแอปของคุณ

  4. iOS : ใน Xcode ให้เปิดใช้งานการแจ้งเตือนแบบพุช สำหรับโปรเจ็กต์ของคุณ & ตรวจสอบให้แน่ใจว่าคีย์การตรวจสอบสิทธิ์ APN ของคุณได้ รับการกำหนดค่าด้วย Firebase Cloud Messaging (FCM) นอกจากนี้ คุณต้อง เปิดใช้งานโหมดเบื้องหลัง สำหรับการแจ้งเตือนระยะไกล หากต้องการดูคำอธิบายเชิงลึกของขั้นตอนนี้ โปรดดูเอกสาร Firebase iOS Phone Auth

  5. เว็บ : ตรวจสอบให้แน่ใจว่าคุณได้เพิ่มโดเมนแอปพลิเคชันของคุณบน คอนโซล Firebase ภายใต้ โดเมนการเปลี่ยนเส้นทาง OAuth

การเปิดใช้งานการรับรองความถูกต้องแบบหลายปัจจัย

  1. เปิดหน้า การตรวจสอบสิทธิ์ > วิธีการลงชื่อเข้าใช้ ของคอนโซล Firebase

  2. ในส่วน ขั้นสูง ให้เปิดใช้งาน SMS Multi-factor Authentication

    คุณควรป้อนหมายเลขโทรศัพท์ที่จะใช้ทดสอบแอปของคุณด้วย แม้ว่าจะเป็นทางเลือก แต่ขอแนะนำอย่างยิ่งให้ลงทะเบียนหมายเลขโทรศัพท์ทดสอบเพื่อหลีกเลี่ยงการควบคุมปริมาณระหว่างการพัฒนา

  3. หากคุณยังไม่ได้อนุญาตโดเมนของแอปของคุณ ให้เพิ่มลงในรายการอนุญาตบนหน้า การตรวจสอบสิทธิ์ > การตั้งค่า ของคอนโซล Firebase

การเลือกรูปแบบการลงทะเบียน

คุณสามารถเลือกได้ว่าแอปของคุณต้องมีการตรวจสอบสิทธิ์แบบหลายปัจจัยหรือไม่ รวมถึงจะลงทะเบียนผู้ใช้อย่างไรและเมื่อใด รูปแบบทั่วไปบางประการ ได้แก่:

  • ลงทะเบียนปัจจัยที่สองของผู้ใช้เป็นส่วนหนึ่งของการลงทะเบียน ใช้วิธีนี้หากแอปของคุณต้องมีการตรวจสอบสิทธิ์แบบหลายปัจจัยสำหรับผู้ใช้ทั้งหมด

  • เสนอตัวเลือกที่ข้ามได้เพื่อลงทะเบียนปัจจัยที่ 2 ระหว่างการลงทะเบียน แอพที่ต้องการสนับสนุน แต่ไม่จำเป็นต้องมีการตรวจสอบสิทธิ์แบบหลายปัจจัยอาจชอบวิธีนี้

  • ให้ความสามารถในการเพิ่มปัจจัยที่สองจากบัญชีของผู้ใช้หรือหน้าการจัดการโปรไฟล์ แทนหน้าจอการลงทะเบียน สิ่งนี้จะช่วยลดความขัดแย้งระหว่างขั้นตอนการลงทะเบียน ในขณะที่ยังคงให้การรับรองความถูกต้องแบบหลายปัจจัยสำหรับผู้ใช้ที่คำนึงถึงความปลอดภัย

  • ต้องเพิ่มปัจจัยที่สองทีละน้อยเมื่อผู้ใช้ต้องการเข้าถึงคุณลักษณะที่มีข้อกำหนดด้านความปลอดภัยที่เพิ่มขึ้น

การลงทะเบียนปัจจัยที่สอง

หากต้องการลงทะเบียนปัจจัยรองใหม่สำหรับผู้ใช้:

  1. ตรวจสอบสิทธิ์ผู้ใช้อีกครั้ง

  2. ขอให้ผู้ใช้ป้อนหมายเลขโทรศัพท์ของตน

  3. รับเซสชันแบบหลายปัจจัยสำหรับผู้ใช้:

    final multiFactorSession = await user.multiFactor.getSession();
    
  4. ยืนยันหมายเลขโทรศัพท์ด้วยเซสชันหลายปัจจัยและการโทรกลับของคุณ:

    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. เมื่อส่งรหัส SMS แล้ว ให้ขอให้ผู้ใช้ยืนยันรหัส:

    final credential = PhoneAuthProvider.credential(
      verificationId: verificationId,
      smsCode: smsCode,
    );
    
  6. ลงทะเบียนให้เสร็จสิ้น:

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

รหัสด้านล่างแสดงตัวอย่างที่สมบูรณ์ของการลงทะเบียนปัจจัยที่สอง:

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

ยินดีด้วย! คุณลงทะเบียนปัจจัยการรับรองความถูกต้องที่สองสำหรับผู้ใช้สำเร็จแล้ว

การลงชื่อเข้าใช้ผู้ใช้ด้วยปัจจัยที่ 2

หากต้องการลงชื่อเข้าใช้ผู้ใช้ด้วยการยืนยัน SMS แบบสองปัจจัย:

  1. ลงชื่อเข้าใช้ผู้ใช้ด้วยปัจจัยแรก จากนั้นตรวจสอบข้อยกเว้น FirebaseAuthMultiFactorException ข้อผิดพลาดนี้มีตัวแก้ไข ซึ่งคุณสามารถใช้เพื่อรับปัจจัยที่สองที่ลงทะเบียนของผู้ใช้ นอกจากนี้ยังมีเซสชันพื้นฐานที่พิสูจน์ว่าผู้ใช้ได้รับการรับรองความถูกต้องด้วยปัจจัยแรกได้สำเร็จ

    ตัวอย่างเช่น หากปัจจัยแรกของผู้ใช้คืออีเมลและรหัสผ่าน:

    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. หากผู้ใช้มีปัจจัยรองหลายรายการที่ลงทะเบียนไว้ ให้ถามผู้ใช้ว่าควรใช้ปัจจัยใด:

    final session = e.resolver.session;
    
    final hint = e.resolver.hints[selectedHint];
    
  3. ส่งข้อความยืนยันไปยังโทรศัพท์ของผู้ใช้พร้อมคำแนะนำและเซสชันแบบหลายปัจจัย:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession: session,
      multiFactorInfo: hint,
      verificationCompleted: (_) {},
      verificationFailed: (_) {},
      codeSent: (String verificationId, int? resendToken) async {
        // ...
      },
      codeAutoRetrievalTimeout: (_) {},
    );
    
  4. เรียก resolver.resolveSignIn() เพื่อดำเนินการตรวจสอบสิทธิ์รองให้เสร็จสิ้น:

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

โค้ดด้านล่างแสดงตัวอย่างที่สมบูรณ์ของการลงชื่อเข้าใช้ผู้ใช้แบบหลายปัจจัย:

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

ยินดีด้วย! คุณลงชื่อเข้าใช้ผู้ใช้โดยใช้การรับรองความถูกต้องแบบหลายปัจจัยสำเร็จแล้ว

อะไรต่อไป