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

หากคุณอัปเกรดเป็น Firebase Authentication with Identity Platform คุณสามารถเพิ่มการตรวจสอบสิทธิ์แบบหลายปัจจัย (MFA) ด้วยรหัสผ่านที่สามารถใช้งานได้เพียงครั้งเดียวตามเวลา (TOTP) ลงในแอปได้

Firebase Authentication with Identity Platform ช่วยให้คุณใช้ TOTP เป็นปัจจัยเพิ่มเติมสำหรับการตรวจสอบสิทธิ์แบบหลายปัจจัยได้ เมื่อเปิดใช้ฟีเจอร์นี้ ผู้ใช้ที่พยายามลงชื่อเข้าใช้แอปจะเห็นคำขอ TOTP หากต้องการสร้าง TOTP ผู้ใช้ต้องใช้แอป Authenticator ที่สร้างรหัส TOTP ที่ถูกต้องได้ เช่น Google Authenticator

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

  1. เปิดใช้ผู้ให้บริการอย่างน้อย 1 รายที่รองรับ MFA โปรดทราบว่าผู้ให้บริการทั้งหมด ยกเว้น ผู้ให้บริการต่อไปนี้รองรับ MFA

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

  3. หากยังไม่ได้ดำเนินการ โปรดติดตั้ง Firebase Apple SDK

    ระบบรองรับ TOTP MFA ใน Apple SDK เวอร์ชัน v10.12.0 ขึ้นไปและใน iOS เท่านั้น

เปิดใช้ TOTP MFA

หากต้องการเปิดใช้ TOTP เป็นปัจจัยที่ 2 ให้ใช้ Admin SDK หรือเรียกใช้ปลายทาง REST ของการกำหนดค่าโปรเจ็กต์

หากต้องการใช้ Admin SDK ให้ทำดังนี้

  1. หากยังไม่ได้ดำเนินการ โปรดติดตั้ง Firebase Admin Node.js SDK

    ระบบรองรับ TOTP MFA ใน Firebase Admin Node.js SDK เวอร์ชัน 11.6.0 ขึ้นไปเท่านั้น

  2. เรียกใช้คำสั่งต่อไปนี้

    import { getAuth } from 'firebase-admin/auth';
    
    getAuth().projectConfigManager().updateProjectConfig(
    {
          multiFactorConfig: {
              providerConfigs: [{
                  state: "ENABLED",
                  totpProviderConfig: {
                      adjacentIntervals: NUM_ADJ_INTERVALS
                  }
              }]
          }
    })
    

    แทนที่ข้อมูลต่อไปนี้

    • NUM_ADJ_INTERVALS: จำนวนช่วงเวลาที่อยู่ติดกันซึ่งจะยอมรับ TOTP ตั้งแต่ 0 ถึง 10 ค่าเริ่มต้นคือ 5

      TOTP ทำงานโดยตรวจสอบว่าเมื่อทั้ง 2 ฝ่าย (ผู้พิสูจน์และผู้ตรวจสอบ) สร้าง OTP ภายในช่วงเวลาเดียวกัน (โดยปกติคือ 30 วินาที) ทั้ง 2 ฝ่ายจะสร้างรหัสผ่านเดียวกัน อย่างไรก็ตาม คุณสามารถกำหนดค่าบริการ TOTP ให้ยอมรับ TOTP จากช่วงเวลาที่อยู่ติดกันได้ด้วย เพื่อรองรับความคลาดเคลื่อนของเวลาในนาฬิกาของทั้ง 2 ฝ่ายและเวลาตอบสนองของมนุษย์

หากต้องการเปิดใช้ TOTP MFA โดยใช้ REST API ให้เรียกใช้คำสั่งต่อไปนี้

curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: PROJECT_ID" \
    -d \
    '{
        "mfa": {
          "providerConfigs": [{
            "state": "ENABLED",
            "totpProviderConfig": {
              "adjacentIntervals": NUM_ADJ_INTERVALS
            }
          }]
       }
    }'

แทนที่ข้อมูลต่อไปนี้

  • PROJECT_ID: รหัสโปรเจ็กต์
  • NUM_ADJ_INTERVALS: จำนวนช่วงเวลา ตั้งแต่ 0 ถึง 10 ค่าเริ่มต้นคือ 5

    TOTP ทำงานโดยตรวจสอบว่าเมื่อทั้ง 2 ฝ่าย (ผู้พิสูจน์และผู้ตรวจสอบ) สร้าง OTP ภายในช่วงเวลาเดียวกัน (โดยปกติคือ 30 วินาที) ทั้ง 2 ฝ่ายจะสร้างรหัสผ่านเดียวกัน อย่างไรก็ตาม คุณสามารถกำหนดค่าบริการ TOTP ให้ยอมรับ TOTP จากช่วงเวลาที่อยู่ติดกันได้ด้วย เพื่อรองรับความคลาดเคลื่อนของเวลาในนาฬิกาของทั้ง 2 ฝ่ายและเวลาตอบสนองของมนุษย์

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

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

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

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

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

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

ลงทะเบียนผู้ใช้ใน TOTP MFA

หลังจากเปิดใช้ TOTP MFA เป็นปัจจัยที่ 2 สำหรับแอปแล้ว ให้ใช้ตรรกะฝั่งไคลเอ็นต์เพื่อลงทะเบียนผู้ใช้ใน TOTP MFA โดยทำดังนี้

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

  2. สร้างข้อมูลลับ TOTP สำหรับผู้ใช้ที่ผ่านการตรวจสอบสิทธิ์

    // Generate a TOTP secret.
    guard let mfaSession = try? await currentUser.multiFactor.session() else { return }
    guard let totpSecret = try? await TOTPMultiFactorGenerator.generateSecret(with: mfaSession) else { return }
    
    // Display the secret to the user and prompt them to enter it into their
    // authenticator app. (See the next step.)
    
  3. แสดงข้อมูลลับให้ผู้ใช้เห็นและแจ้งให้ผู้ใช้ป้อนข้อมูลลับดังกล่าวลงในแอป Authenticator

    // Display this key:
    let secret = totpSecret.sharedSecretKey()
    

    นอกจากการแสดงคีย์ลับแล้ว คุณยังพยายามเพิ่มคีย์ลับลงในแอป Authenticator เริ่มต้นของอุปกรณ์โดยอัตโนมัติได้ด้วย โดยสร้าง URI ของคีย์ที่เข้ากันได้กับ Google Authenticator แล้วส่ง URI ดังกล่าวไปยัง openInOTPApp(withQRCodeURL:)

    let otpAuthUri = totpSecret.generateQRCodeURL(
        withAccountName: currentUser.email ?? "default account",
        issuer: "Your App Name")
    totpSecret.openInOTPApp(withQRCodeURL: otpAuthUri)
    

    หลังจากที่ผู้ใช้เพิ่มข้อมูลลับลงในแอป Authenticator แล้ว แอปจะเริ่มสร้าง TOTP

  4. แจ้งให้ผู้ใช้พิมพ์ TOTP ที่แสดงโดยแอป Authenticator และใช้ TOTP ดังกล่าวเพื่อลงทะเบียน MFA ให้เสร็จสมบูรณ์

    // Ask the user for a verification code from the authenticator app.
    let verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    let multiFactorAssertion = TOTPMultiFactorGenerator.assertionForEnrollment(
        with: totpSecret,
        oneTimePassword: verificationCode)
    do {
        try await currentUser.multiFactor.enroll(
            with: multiFactorAssertion,
            displayName: "TOTP")
    } catch {
        // Wrong or expired OTP. Re-prompt the user.
    }
    

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

หากต้องการลงชื่อเข้าใช้ผู้ใช้ด้วย TOTP MFA ให้ใช้โค้ดต่อไปนี้

  1. เรียกใช้เมธอด signIn(with...:)- เมธอดใดเมธอดหนึ่งเช่นเดียวกับที่คุณจะทำหากไม่ได้ใช้ MFA (เช่น signIn(withEmail:password:)) หากเมธอดแสดงข้อผิดพลาดที่มีโค้ด secondFactorRequired ให้เริ่มขั้นตอน MFA ของแอป

    do {
        let authResult = try await Auth.auth().signIn(withEmail: email, password: password)
    
        // If the user is not enrolled with a second factor and provided valid
        // credentials, sign-in succeeds.
    
        // (If your app requires MFA, this could be considered an error
        // condition, which you would resolve by forcing the user to enroll a
        // second factor.)
    
        // ...
    } catch let error as AuthErrorCode where error.code == .secondFactorRequired {
        // Initiate your second factor sign-in flow. (See next step.)
        // ...
    } catch {
        // Other auth error.
        throw error
    }
    
  2. ขั้นตอน MFA ของแอปควรแจ้งให้ผู้ใช้เลือกปัจจัยที่ 2 ที่ต้องการใช้ก่อน คุณดูรายการปัจจัยที่ 2 ที่รองรับได้โดยตรวจสอบพร็อพเพอร์ตี้ hints ของอินสแตนซ์ MultiFactorResolver

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. หากผู้ใช้เลือกใช้ TOTP ให้แจ้งให้ผู้ใช้พิมพ์ TOTP ที่แสดงในแอป Authenticator และใช้ TOTP ดังกล่าวเพื่อลงชื่อเข้าใช้

    let multiFactorInfo = resolver.hints[selectedIndex]
    switch multiFactorInfo.factorID {
    case TOTPMultiFactorID:
        let otpFromAuthenticator = // OTP typed by the user.
        let assertion = TOTPMultiFactorGenerator.assertionForSignIn(
            withEnrollmentID: multiFactorInfo.uid,
            oneTimePassword: otpFromAuthenticator)
        do {
            let authResult = try await resolver.resolveSignIn(with: assertion)
        } catch {
            // Wrong or expired OTP. Re-prompt the user.
        }
    default:
        return
    }
    

ยกเลิกการลงทะเบียนจาก TOTP MFA

ส่วนนี้อธิบายวิธีจัดการเมื่อผู้ใช้ยกเลิกการลงทะเบียนจาก TOTP MFA

หากผู้ใช้ลงชื่อสมัครใช้ตัวเลือก MFA หลายรายการ และยกเลิกการลงทะเบียนจากตัวเลือกที่เปิดใช้ล่าสุด ผู้ใช้จะได้รับข้อความ auth/user-token-expired และออกจากระบบ ผู้ใช้ต้องลงชื่อเข้าใช้อีกครั้งและยืนยันข้อมูลเข้าสู่ระบบที่มีอยู่ เช่น ที่อยู่อีเมลและรหัสผ่าน

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

guard let currentUser = Auth.auth().currentUser else { return }

// Prompt the user to select a factor to unenroll, from this array:
currentUser.multiFactor.enrolledFactors

// ...

// Unenroll the second factor.
let multiFactorInfo = currentUser.multiFactor.enrolledFactors[selectedIndex]
do {
    try await currentUser.multiFactor.unenroll(with: multiFactorInfo)
} catch let error as AuthErrorCode where error.code == .invalidUserToken {
    // Second factor unenrolled, but the user was signed out. Re-authenticate
    // them.
}

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