เพิ่มการตรวจสอบสิทธิ์แบบหลายปัจจัยในแอป Flutter

หากอัปเกรดเป็น Firebase Authentication ที่มี Identity Platform แล้ว คุณจะเพิ่มการตรวจสอบสิทธิ์แบบหลายปัจจัยทาง SMS ลงในแอป Flutter ได้

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

ก่อนเริ่มต้น

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

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

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

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

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

การเปิดใช้การตรวจสอบสิทธิ์แบบหลายปัจจัย

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

  2. ในส่วนขั้นสูง ให้เปิดใช้การตรวจสอบสิทธิ์แบบหลายปัจจัยทาง SMS

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

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

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

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

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

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

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

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

การลงทะเบียนปัจจัยที่ 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,
      ),
    );
    

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

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

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

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

วิธีลงชื่อเข้าใช้ผู้ใช้ด้วยการยืนยันแบบ 2 ขั้นตอนผ่าน SMS

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

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

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

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

ขั้นตอนถัดไป