หากอัปเกรดเป็น Firebase Authentication with Identity Platform แล้ว คุณจะเพิ่มการตรวจสอบสิทธิ์แบบหลายปัจจัยทาง SMS ลงในแอป Android ได้
การตรวจสอบสิทธิ์แบบหลายปัจจัยช่วยเพิ่มความปลอดภัยให้แอปของคุณ แม้ว่าผู้โจมตีมักเจาะรหัสผ่านและบัญชีโซเชียล แต่การสกัดกั้นข้อความมีความซับซ้อนมากกว่า
ก่อนเริ่มต้น
เปิดใช้ผู้ให้บริการอย่างน้อย 1 รายที่รองรับการตรวจสอบสิทธิ์แบบหลายปัจจัย ผู้ให้บริการทุกรายรองรับ MFA ยกเว้นการตรวจสอบสิทธิ์ทางโทรศัพท์ การตรวจสอบสิทธิ์แบบไม่ระบุชื่อ และ Game Center ของ Apple
ตรวจสอบว่าแอปของคุณยืนยันอีเมลของผู้ใช้ MFA ต้องมีการยืนยันอีเมล ซึ่งจะช่วยป้องกันไม่ให้ผู้ไม่ประสงค์ดีลงทะเบียนใช้บริการด้วยอีเมลที่ตนเองไม่ได้เป็นเจ้าของ แล้วล็อกเจ้าของตัวจริงไม่ให้เข้าถึงบัญชีโดยการเพิ่มการยืนยันแบบ 2 ขั้นตอน
ลงทะเบียนแฮช SHA-1 ของแอปในคอนโซล Firebase (ระบบจะโอนการเปลี่ยนแปลงของคุณไปยัง Google Cloud Firebase โดยอัตโนมัติ)
ทำตามขั้นตอนใน การตรวจสอบสิทธิ์ไคลเอ็นต์ เพื่อรับแฮช SHA-1 ของแอป
เปิดคอนโซล Firebase
ไปที่การตั้งค่าโปรเจ็กต์
คลิกไอคอน Android ในส่วนแอปของคุณ
ทำตามขั้นตอนที่แนะนำเพื่อเพิ่มแฮช SHA-1
การเปิดใช้การตรวจสอบสิทธิ์แบบหลายปัจจัย
เปิดหน้าการตรวจสอบสิทธิ์ > วิธีการลงชื่อเข้าใช้ ของคอนโซล Firebase
ในส่วนขั้นสูง ให้เปิดใช้การตรวจสอบสิทธิ์แบบหลายปัจจัยทาง SMS
นอกจากนี้ คุณควรป้อนหมายเลขโทรศัพท์ที่จะใช้ทดสอบแอปด้วย แม้ว่าการลงทะเบียนหมายเลขโทรศัพท์ทดสอบจะไม่บังคับ แต่เราขอแนะนำให้ลงทะเบียนเพื่อ หลีกเลี่ยงการจำกัดอัตราในระหว่างการพัฒนา
หากยังไม่ได้ให้สิทธิ์โดเมนของแอป ให้เพิ่มโดเมนลงในรายการที่อนุญาตในหน้าการตรวจสอบสิทธิ์ > การตั้งค่า ของคอนโซล Firebase
ไม่บังคับ: ในหน้าการตรวจสอบสิทธิ์ > การตั้งค่า ให้ตั้งค่านโยบายใน ภูมิภาคที่คุณต้องการอนุญาตหรือปฏิเสธการส่งข้อความ SMS การตั้งค่านโยบายภูมิภาค SMS จะช่วยปกป้องแอปจากการละเมิด SMS ได้
การเลือกรูปแบบการลงทะเบียน
คุณเลือกได้ว่าแอปต้องใช้การตรวจสอบสิทธิ์แบบหลายปัจจัยหรือไม่ รวมถึงวิธี และเวลาในการลงทะเบียนผู้ใช้ รูปแบบที่พบบ่อยมีดังนี้
ลงทะเบียนปัจจัยที่สองของผู้ใช้เป็นส่วนหนึ่งของการลงทะเบียน ใช้วิธีนี้หากแอปกำหนดให้ผู้ใช้ทุกคนต้องใช้การตรวจสอบสิทธิ์แบบหลายปัจจัย
เสนอตัวเลือกที่ข้ามได้เพื่อลงทะเบียนปัจจัยที่ 2 ในระหว่างการลงทะเบียน แอป ที่ต้องการแนะนำให้ใช้การตรวจสอบสิทธิ์แบบหลายปัจจัยแต่ไม่บังคับ อาจชอบแนวทางนี้
ให้ความสามารถในการเพิ่มปัจจัยที่ 2 จากหน้าการจัดการบัญชีหรือโปรไฟล์ของผู้ใช้แทนหน้าจอลงชื่อสมัครใช้ วิธีนี้จะช่วยลดความยุ่งยากในระหว่าง กระบวนการลงทะเบียน ขณะเดียวกันก็ยังคง เปิดใช้การตรวจสอบสิทธิ์แบบหลายปัจจัยสำหรับผู้ใช้ที่คำนึงถึงความปลอดภัย
กำหนดให้เพิ่มปัจจัยที่ 2 ทีละรายการเมื่อผู้ใช้ต้องการเข้าถึงฟีเจอร์ที่มีข้อกำหนดด้านความปลอดภัยที่สูงขึ้น
การลงทะเบียนปัจจัยที่ 2
วิธีลงทะเบียนปัจจัยที่สองใหม่สำหรับผู้ใช้
ตรวจสอบสิทธิ์ผู้ใช้อีกครั้ง
ขอให้ผู้ใช้ป้อนหมายเลขโทรศัพท์
รับเซสชันแบบหลายปัจจัยสำหรับผู้ใช้
Kotlin
user.multiFactor.session.addOnCompleteListener { task -> if (task.isSuccessful) { val multiFactorSession: MultiFactorSession? = task.result } }Java
user.getMultiFactor().getSession() .addOnCompleteListener( new OnCompleteListener<MultiFactorSession>() { @Override public void onComplete(@NonNull Task<MultiFactorSession> task) { if (task.isSuccessful()) { MultiFactorSession multiFactorSession = task.getResult(); } } });สร้างออบเจ็กต์
OnVerificationStateChangedCallbacksเพื่อจัดการเหตุการณ์ต่างๆ ในกระบวนการยืนยันKotlin
val callbacks = object : OnVerificationStateChangedCallbacks() { override fun onVerificationCompleted(credential: PhoneAuthCredential) { // This callback will be invoked in two situations: // 1) Instant verification. In some cases, the phone number can be // instantly verified without needing to send or enter a verification // code. You can disable this feature by calling // PhoneAuthOptions.builder#requireSmsValidation(true) when building // the options to pass to PhoneAuthProvider#verifyPhoneNumber(). // 2) Auto-retrieval. On some devices, Google Play services can // automatically detect the incoming verification SMS and perform // verification without user action. this@MainActivity.credential = credential } override fun onVerificationFailed(e: FirebaseException) { // This callback is invoked in response to invalid requests for // verification, like an incorrect phone number. if (e is FirebaseAuthInvalidCredentialsException) { // Invalid request // ... } else if (e is FirebaseTooManyRequestsException) { // The SMS quota for the project has been exceeded // ... } // Show a message and update the UI // ... } override fun onCodeSent( verificationId: String, forceResendingToken: ForceResendingToken ) { // The SMS verification code has been sent to the provided phone number. // We now need to ask the user to enter the code and then construct a // credential by combining the code with a verification ID. // Save the verification ID and resending token for later use. this@MainActivity.verificationId = verificationId this@MainActivity.forceResendingToken = forceResendingToken // ... } }Java
OnVerificationStateChangedCallbacks callbacks = new OnVerificationStateChangedCallbacks() { @Override public void onVerificationCompleted(PhoneAuthCredential credential) { // This callback will be invoked in two situations: // 1) Instant verification. In some cases, the phone number can be // instantly verified without needing to send or enter a verification // code. You can disable this feature by calling // PhoneAuthOptions.builder#requireSmsValidation(true) when building // the options to pass to PhoneAuthProvider#verifyPhoneNumber(). // 2) Auto-retrieval. On some devices, Google Play services can // automatically detect the incoming verification SMS and perform // verification without user action. this.credential = credential; } @Override public void onVerificationFailed(FirebaseException e) { // This callback is invoked in response to invalid requests for // verification, like an incorrect phone number. if (e instanceof FirebaseAuthInvalidCredentialsException) { // Invalid request // ... } else if (e instanceof FirebaseTooManyRequestsException) { // The SMS quota for the project has been exceeded // ... } // Show a message and update the UI // ... } @Override public void onCodeSent( String verificationId, PhoneAuthProvider.ForceResendingToken token) { // The SMS verification code has been sent to the provided phone number. // We now need to ask the user to enter the code and then construct a // credential by combining the code with a verification ID. // Save the verification ID and resending token for later use. this.verificationId = verificationId; this.forceResendingToken = token; // ... } };เริ่มต้นออบเจ็กต์
PhoneInfoOptionsด้วยหมายเลขโทรศัพท์ของผู้ใช้ เซสชันแบบหลายปัจจัย และการเรียกกลับของคุณKotlin
val phoneAuthOptions = PhoneAuthOptions.newBuilder() .setPhoneNumber(phoneNumber) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(MultiFactorSession) .setCallbacks(callbacks) .build()Java
PhoneAuthOptions phoneAuthOptions = PhoneAuthOptions.newBuilder() .setPhoneNumber(phoneNumber) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(multiFactorSession) .setCallbacks(callbacks) .build();โดยค่าเริ่มต้น ระบบจะเปิดใช้การยืนยันทันที หากต้องการปิดใช้ ให้เพิ่มการเรียกใช้ ไปยัง
requireSmsValidation(true)ส่งข้อความยืนยันไปยังโทรศัพท์ของผู้ใช้
Kotlin
PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions)Java
PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions);แม้ว่าจะไม่บังคับ แต่แนวทางปฏิบัติแนะนำคือการแจ้งให้ผู้ใช้ทราบล่วงหน้าว่า ผู้ใช้จะได้รับข้อความ SMS และจะมีการคิดอัตราค่าบริการมาตรฐาน
เมื่อส่งรหัส SMS แล้ว ให้ขอให้ผู้ใช้ยืนยันรหัสโดยทำดังนี้
Kotlin
// Ask user for the verification code. val credential = PhoneAuthProvider.getCredential(verificationId, verificationCode)Java
// Ask user for the verification code. PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, verificationCode);เริ่มต้นออบเจ็กต์
MultiFactorAssertionด้วยPhoneAuthCredentialดังนี้Kotlin
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)Java
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);ลงทะเบียนให้เสร็จสมบูรณ์ คุณระบุชื่อที่แสดงสำหรับ ปัจจัยที่ 2 ได้ (ไม่บังคับ) ซึ่งจะเป็นประโยชน์สำหรับผู้ใช้ที่มีปัจจัยที่สองหลายรายการ เนื่องจากระบบจะมาสก์หมายเลขโทรศัพท์ในระหว่างขั้นตอนการตรวจสอบสิทธิ์ (เช่น +1******1234)
Kotlin
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. FirebaseAuth.getInstance() .currentUser ?.multiFactor ?.enroll(multiFactorAssertion, "My personal phone number") ?.addOnCompleteListener { // ... }Java
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. FirebaseAuth.getInstance() .getCurrentUser() .getMultiFactor() .enroll(multiFactorAssertion, "My personal phone number") .addOnCompleteListener( new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // ... } });
โค้ดด้านล่างแสดงตัวอย่างที่สมบูรณ์ของการลงทะเบียนปัจจัยที่ 2
Kotlin
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)
user.multiFactor.session
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            val multiFactorSession = task.result
            val phoneAuthOptions = PhoneAuthOptions.newBuilder()
                .setPhoneNumber(phoneNumber)
                .setTimeout(30L, TimeUnit.SECONDS)
                .setMultiFactorSession(multiFactorSession)
                .setCallbacks(callbacks)
                .build()
            // Send SMS verification code.
            PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions)
        }
    }
// Ask user for the verification code.
val credential = PhoneAuthProvider.getCredential(verificationId, verificationCode)
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)
// Complete enrollment.
FirebaseAuth.getInstance()
    .currentUser
    ?.multiFactor
    ?.enroll(multiFactorAssertion, "My personal phone number")
    ?.addOnCompleteListener {
        // ...
    }
Java
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
user.getMultiFactor().getSession()
  .addOnCompleteListener(
      new OnCompleteListener<MultiFactorSession>() {
      @Override
      public void onComplete(@NonNull Task<MultiFactorSession> task) {
        if (task.isSuccessful()) {
          MultiFactorSession multiFactorSession = task.getResult();
          PhoneAuthOptions phoneAuthOptions =
            PhoneAuthOptions.newBuilder()
                .setPhoneNumber(phoneNumber)
                .setTimeout(30L, TimeUnit.SECONDS)
                .setMultiFactorSession(multiFactorSession)
                .setCallbacks(callbacks)
                .build();
          // Send SMS verification code.
          PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions);
        }
      }
      });
// Ask user for the verification code.
PhoneAuthCredential credential =
  PhoneAuthProvider.getCredential(verificationId, verificationCode);
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
// Complete enrollment.
FirebaseAuth.getInstance()
  .getCurrentUser()
  .getMultiFactor()
  .enroll(multiFactorAssertion, "My personal phone number")
  .addOnCompleteListener(
      new OnCompleteListener<Void>() {
      @Override
      public void onComplete(@NonNull Task<Void> task) {
        // ...
      }
      });
ยินดีด้วย คุณลงทะเบียนปัจจัยการตรวจสอบสิทธิ์ที่ 2 สำหรับ ผู้ใช้เรียบร้อยแล้ว
การลงชื่อเข้าใช้ของผู้ใช้ด้วยปัจจัยที่สอง
วิธีลงชื่อเข้าใช้ผู้ใช้ด้วยการยืนยันทาง SMS แบบ 2 ปัจจัย
ลงชื่อเข้าใช้ผู้ใช้ด้วยปัจจัยแรก จากนั้นดักจับข้อยกเว้น
FirebaseAuthMultiFactorExceptionข้อผิดพลาดนี้มีตัวแก้ไข ซึ่งคุณใช้เพื่อรับปัจจัยที่ 2 ที่ผู้ใช้ลงทะเบียนไว้ได้ นอกจากนี้ ยังมีเซสชันพื้นฐานที่พิสูจน์ว่าผู้ใช้ได้ตรวจสอบสิทธิ์ด้วยปัจจัยแรกเรียบร้อยแล้วเช่น หากปัจจัยแรกของผู้ใช้คืออีเมลและรหัสผ่าน
Kotlin
FirebaseAuth.getInstance() .signInWithEmailAndPassword(email, password) .addOnCompleteListener( OnCompleteListener { task -> if (task.isSuccessful) { // User is not enrolled with a second factor and is successfully // signed in. // ... return@OnCompleteListener } if (task.exception is FirebaseAuthMultiFactorException) { // The user is a multi-factor user. Second factor challenge is // required. val multiFactorResolver = (task.exception as FirebaseAuthMultiFactorException).resolver // ... } else { // Handle other errors, such as wrong password. } })Java
FirebaseAuth.getInstance() .signInWithEmailAndPassword(email, password) .addOnCompleteListener( new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { // User is not enrolled with a second factor and is successfully // signed in. // ... return; } if (task.getException() instanceof FirebaseAuthMultiFactorException) { // The user is a multi-factor user. Second factor challenge is // required. MultiFactorResolver multiFactorResolver = task.getException().getResolver(); // ... } else { // Handle other errors such as wrong password. } } });หากปัจจัยแรกของผู้ใช้เป็นผู้ให้บริการแบบรวม เช่น OAuth ให้ตรวจหาข้อผิดพลาดหลังจากเรียกใช้
startActivityForSignInWithProvider()หากผู้ใช้ลงทะเบียนปัจจัยที่สองไว้หลายรายการ ให้ถามผู้ใช้ว่าต้องการใช้ปัจจัยใด
Kotlin
// Ask user which second factor to use. // You can get the list of enrolled second factors using // multiFactorResolver.hints // Check the selected factor: if (multiFactorResolver.hints[selectedIndex].factorId === PhoneMultiFactorGenerator.FACTOR_ID ) { // User selected a phone second factor. val selectedHint = multiFactorResolver.hints[selectedIndex] as PhoneMultiFactorInfo } else if (multiFactorResolver.hints[selectedIndex].factorId === TotpMultiFactorGenerator.FACTOR_ID) { // User selected a TOTP second factor. } else { // Unsupported second factor. }Java
// Ask user which second factor to use. // You can get the masked phone number using // resolver.getHints().get(selectedIndex).getPhoneNumber() // You can get the display name using // resolver.getHints().get(selectedIndex).getDisplayName() if ( resolver.getHints() .get(selectedIndex) .getFactorId() .equals( PhoneMultiFactorGenerator.FACTOR_ID ) ) { // User selected a phone second factor. MultiFactorInfo selectedHint = multiFactorResolver.getHints().get(selectedIndex); } else if ( resolver .getHints() .get(selectedIndex) .getFactorId() .equals(TotpMultiFactorGenerator.FACTOR_ID ) ) { // User selected a TOTP second factor. } else { // Unsupported second factor. }เริ่มต้นออบเจ็กต์
PhoneAuthOptionsด้วยคำใบ้และเซสชันแบบหลายปัจจัย ค่าเหล่านี้อยู่ในตัวแก้ไขที่แนบมากับFirebaseAuthMultiFactorExceptionKotlin
val phoneAuthOptions = PhoneAuthOptions.newBuilder() .setMultiFactorHint(selectedHint) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(multiFactorResolver.session) .setCallbacks(callbacks) // Optionally disable instant verification. // .requireSmsValidation(true) .build()Java
PhoneAuthOptions phoneAuthOptions = PhoneAuthOptions.newBuilder() .setMultiFactorHint(selectedHint) .setTimeout(30L, TimeUnit.SECONDS) .setMultiFactorSession(multiFactorResolver.getSession()) .setCallbacks(callbacks) // Optionally disable instant verification. // .requireSmsValidation(true) .build();ส่งข้อความยืนยันไปยังโทรศัพท์ของผู้ใช้
Kotlin
// Send SMS verification code PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions)Java
// Send SMS verification code PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptions);เมื่อส่งรหัส SMS แล้ว ให้ขอให้ผู้ใช้ยืนยันรหัสโดยทำดังนี้
Kotlin
// Ask user for the verification code. Then, pass it to getCredential: val credential = PhoneAuthProvider.getCredential(verificationId, verificationCode)Java
// Ask user for the verification code. Then, pass it to getCredential: PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, verificationCode);เริ่มต้นออบเจ็กต์
MultiFactorAssertionด้วยPhoneAuthCredentialดังนี้Kotlin
val multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential)Java
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);โทรหา
resolver.resolveSignIn()เพื่อทำการตรวจสอบสิทธิ์รองให้เสร็จสมบูรณ์ จากนั้นคุณจะเข้าถึงผลการลงชื่อเข้าใช้เดิมได้ ซึ่งรวมถึง ข้อมูลเฉพาะของผู้ให้บริการมาตรฐานและข้อมูลเข้าสู่ระบบการตรวจสอบสิทธิ์Kotlin
multiFactorResolver .resolveSignIn(multiFactorAssertion) .addOnCompleteListener { task -> if (task.isSuccessful) { val authResult = task.result // AuthResult will also contain the user, additionalUserInfo, // and an optional credential (null for email/password) // associated with the first factor sign-in. // For example, if the user signed in with Google as a first // factor, authResult.getAdditionalUserInfo() will contain data // related to Google provider that the user signed in with; // authResult.getCredential() will contain the Google OAuth // credential; // authResult.getCredential().getAccessToken() will contain the // Google OAuth access token; // authResult.getCredential().getIdToken() contains the Google // OAuth ID token. } }Java
multiFactorResolver .resolveSignIn(multiFactorAssertion) .addOnCompleteListener( new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { AuthResult authResult = task.getResult(); // AuthResult will also contain the user, additionalUserInfo, // and an optional credential (null for email/password) // associated with the first factor sign-in. // For example, if the user signed in with Google as a first // factor, authResult.getAdditionalUserInfo() will contain data // related to Google provider that the user signed in with. // authResult.getCredential() will contain the Google OAuth // credential. // authResult.getCredential().getAccessToken() will contain the // Google OAuth access token. // authResult.getCredential().getIdToken() contains the Google // OAuth ID token. } } });
โค้ดด้านล่างแสดงตัวอย่างการลงชื่อเข้าใช้ของผู้ใช้ที่ต้องใช้การยืนยันแบบ 2 ขั้นตอน
Kotlin
FirebaseAuth.getInstance()
    .signInWithEmailAndPassword(email, password)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            // User is not enrolled with a second factor and is successfully
            // signed in.
            // ...
            return@addOnCompleteListener
        }
        if (task.exception is FirebaseAuthMultiFactorException) {
            val multiFactorResolver =
                (task.exception as FirebaseAuthMultiFactorException).resolver
            // Ask user which second factor to use. Then, get
            // the selected hint:
            val selectedHint =
                multiFactorResolver.hints[selectedIndex] as PhoneMultiFactorInfo
            // Send the SMS verification code.
            PhoneAuthProvider.verifyPhoneNumber(
                PhoneAuthOptions.newBuilder()
                    .setActivity(this)
                    .setMultiFactorSession(multiFactorResolver.session)
                    .setMultiFactorHint(selectedHint)
                    .setCallbacks(generateCallbacks())
                    .setTimeout(30L, TimeUnit.SECONDS)
                    .build()
            )
            // Ask user for the SMS verification code, then use it to get
            // a PhoneAuthCredential:
            val credential =
                PhoneAuthProvider.getCredential(verificationId, verificationCode)
            // Initialize a MultiFactorAssertion object with the
            // PhoneAuthCredential.
            val multiFactorAssertion: MultiFactorAssertion =
                PhoneMultiFactorGenerator.getAssertion(credential)
            // Complete sign-in.
            multiFactorResolver
                .resolveSignIn(multiFactorAssertion)
                .addOnCompleteListener { task ->
                    if (task.isSuccessful) {
                        // User successfully signed in with the
                        // second factor phone number.
                    }
                    // ...
                }
        } else {
            // Handle other errors such as wrong password.
        }
    }
Java
FirebaseAuth.getInstance()
  .signInWithEmailAndPassword(email, password)
  .addOnCompleteListener(
      new OnCompleteListener<AuthResult>() {
      @Override
      public void onComplete(@NonNull Task<AuthResult> task) {
        if (task.isSuccessful()) {
          // User is not enrolled with a second factor and is successfully
          // signed in.
          // ...
          return;
        }
        if (task.getException() instanceof FirebaseAuthMultiFactorException) {
          FirebaseAuthMultiFactorException e =
            (FirebaseAuthMultiFactorException) task.getException();
          MultiFactorResolver multiFactorResolver = e.getResolver();
          // Ask user which second factor to use.
          MultiFactorInfo selectedHint =
            multiFactorResolver.getHints().get(selectedIndex);
          // Send the SMS verification code.
          PhoneAuthProvider.verifyPhoneNumber(
            PhoneAuthOptions.newBuilder()
                .setActivity(this)
                .setMultiFactorSession(multiFactorResolver.getSession())
                .setMultiFactorHint(selectedHint)
                .setCallbacks(generateCallbacks())
                .setTimeout(30L, TimeUnit.SECONDS)
                .build());
          // Ask user for the SMS verification code.
          PhoneAuthCredential credential =
            PhoneAuthProvider.getCredential(verificationId, verificationCode);
          // Initialize a MultiFactorAssertion object with the
          // PhoneAuthCredential.
          MultiFactorAssertion multiFactorAssertion =
            PhoneMultiFactorGenerator.getAssertion(credential);
          // Complete sign-in.
          multiFactorResolver
            .resolveSignIn(multiFactorAssertion)
            .addOnCompleteListener(
                new OnCompleteListener<AuthResult>() {
                  @Override
                  public void onComplete(@NonNull Task<AuthResult> task) {
                  if (task.isSuccessful()) {
                    // User successfully signed in with the
                    // second factor phone number.
                  }
                  // ...
                  }
                });
        } else {
          // Handle other errors such as wrong password.
        }
      }
      });
ยินดีด้วย คุณลงชื่อเข้าใช้ผู้ใช้โดยใช้การตรวจสอบสิทธิ์แบบหลายปัจจัย เรียบร้อยแล้ว
ขั้นตอนถัดไป
- จัดการผู้ใช้ที่ใช้การยืนยันแบบ 2 ขั้นตอน แบบเป็นโปรแกรมด้วย Admin SDK