Thêm tính năng xác thực đa yếu tố TOTP vào ứng dụng iOS

Nếu đã nâng cấp lên Firebase Authentication with Identity Platform, bạn có thể thêm tính năng xác thực đa yếu tố (MFA) bằng mật khẩu một lần dựa trên thời gian (TOTP) vào ứng dụng của mình.

Firebase Authentication with Identity Platform cho phép bạn sử dụng TOTP làm yếu tố bổ sung cho MFA. Khi bạn bật tính năng này, người dùng cố gắng đăng nhập vào ứng dụng của bạn sẽ thấy yêu cầu TOTP. Để tạo mã này, họ phải sử dụng một ứng dụng xác thực có thể tạo mã TOTP hợp lệ, chẳng hạn như Google Authenticator.

Trước khi bắt đầu

  1. Bật ít nhất một nhà cung cấp hỗ trợ phương thức xác thực nhiều yếu tố. Xin lưu ý rằng tất cả các trình cung cấp ngoại trừ các trình cung cấp sau đây đều hỗ trợ MFA:

    • Xác thực qua điện thoại
    • Xác thực ẩn danh
    • Mã thông báo xác thực tuỳ chỉnh
    • Apple Game Center
  2. Đảm bảo ứng dụng của bạn xác minh địa chỉ email của người dùng. Phương thức xác thực nhiều yếu tố yêu cầu xác minh email. Điều này giúp ngăn chặn những kẻ độc hại đăng ký một dịch vụ bằng địa chỉ email mà họ không sở hữu, sau đó khoá chủ sở hữu thực sự của địa chỉ email đó bằng cách thêm một yếu tố thứ hai.

  3. Nếu bạn chưa cài đặt, hãy cài đặt SDK Firebase Apple.

    Phương thức xác thực đa yếu tố TOTP chỉ được hỗ trợ trên SDK Apple phiên bản 10.12.0 trở lên và chỉ trên iOS.

Bật phương thức xác thực đa yếu tố TOTP

Để bật TOTP làm yếu tố thứ hai, hãy sử dụng Admin SDK hoặc gọi điểm cuối REST của cấu hình dự án.

Để sử dụng Admin SDK, hãy làm như sau:

  1. Nếu bạn chưa cài đặt, hãy cài đặt SDK Node.js dành cho quản trị viên Firebase.

    Phương thức xác thực đa yếu tố TOTP chỉ được hỗ trợ trên SDK Node.js dành cho quản trị viên Firebase phiên bản 11.6.0 trở lên.

  2. Chạy lệnh sau:

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

    Thay thế nội dung sau:

    • NUM_ADJ_INTERVALS: Số khoảng thời gian cửa sổ thời gian liền kề mà từ 0 đến 10 khoảng thời gian để chấp nhận TOTP. Giá trị mặc định là 5.

      TOTP hoạt động bằng cách đảm bảo rằng khi hai bên (bên xác minh và bên xác thực) tạo OTP trong cùng một khoảng thời gian (thường là 30 giây), thì họ sẽ tạo cùng một mật khẩu. Tuy nhiên, để điều chỉnh độ trễ đồng hồ giữa các bên và thời gian phản hồi của con người, bạn có thể định cấu hình dịch vụ TOTP để cũng chấp nhận TOTP từ các cửa sổ liền kề.

Để bật tính năng xác thực đa yếu tố TOTP bằng API REST, hãy chạy mã sau:

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
            }
          }]
       }
    }'

Thay thế nội dung sau:

  • PROJECT_ID: Mã dự án.
  • NUM_ADJ_INTERVALS: Số khoảng thời gian của cửa sổ, từ 0 đến 10. Giá trị mặc định là 5.

    TOTP hoạt động bằng cách đảm bảo rằng khi hai bên (người chứng minh và trình xác thực) tạo OTP trong cùng một khoảng thời gian (thường dài 30 giây), họ sẽ tạo cùng một mật khẩu. Tuy nhiên, để điều chỉnh độ trễ đồng hồ giữa các bên và thời gian phản hồi của con người, bạn có thể định cấu hình dịch vụ TOTP để cũng chấp nhận TOTP từ các cửa sổ liền kề.

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

Bạn có thể chọn xem ứng dụng của mình có yêu cầu xác thực đa yếu tố hay không, cũng như cách thức và thời điểm đăng ký người dùng. Sau đây là một số mẫu phổ biến:

  • Đăng ký yếu tố thứ hai của người dùng trong quá trình đăng ký. Sử dụng phương thức này nếu ứng dụng của bạn yêu cầu xác thực đa yếu tố cho 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ý. Nếu muốn khuyến khích nhưng không bắt buộc phải xác thực đa yếu tố trong ứng dụng, bạn có thể sử dụng phương pháp này.

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

  • Yêu cầu thêm tăng dần yếu tố thứ hai khi người dùng muốn truy cập vào các tính năng có yêu cầu bảo mật cao hơn.

Đăng ký người dùng sử dụng phương thức xác thực đa yếu tố TOTP

Sau khi bạn bật TOTP MFA làm yếu tố thứ hai cho ứng dụng, hãy triển khai logic phía máy khách để đăng ký người dùng vào TOTP MFA:

  1. Xác thực lại người dùng.

  2. Tạo mã bí mật TOTP cho người dùng đã xác thực:

    // 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. Hiển thị khoá bí mật cho người dùng và nhắc họ nhập khoá đó vào ứng dụng trình xác thực:

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

    Ngoài việc hiển thị khoá bí mật, bạn có thể thử tự động thêm khoá đó vào ứng dụng trình xác thực mặc định của thiết bị. Để làm như vậy, hãy tạo một URI khoá tương thích với Google Authenticator và truyền URI đó đến openInOTPApp(withQRCodeURL:):

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

    Sau khi người dùng thêm khoá bí mật của họ vào ứng dụng xác thực, ứng dụng đó sẽ bắt đầu tạo các TOTP.

  4. Nhắc người dùng nhập mã TOTP do ứng dụng xác thực của họ hiển thị và sử dụng mã này để hoàn tất quy trình đăng ký phương thức xác thực đa yếu tố:

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

Đăng nhập người dùng bằng yếu tố thứ hai

Để đăng nhập người dùng bằng phương thức xác thực đa yếu tố TOTP, hãy sử dụng mã sau:

  1. Gọi một trong các phương thức signIn(with...:)- như cách bạn không sử dụng MFA (ví dụ: signIn(withEmail:password:)). Nếu phương thức đó gây ra lỗi với mã secondFactorRequired, hãy bắt đầu luồng MFA của ứng dụng.

    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. Trước tiên, quy trình xác thực nhiều yếu tố của ứng dụng phải nhắc người dùng chọn yếu tố thứ hai mà họ muốn sử dụng. Bạn có thể xem danh sách các yếu tố thứ hai được hỗ trợ bằng cách kiểm tra thuộc tính hints của thực thể MultiFactorResolver:

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. Nếu người dùng chọn sử dụng TOTP, hãy nhắc họ nhập TOTP hiển thị trên ứng dụng xác thực và sử dụng mã đó để đăng nhập:

    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
    }
    

Huỷ đăng ký phương thức xác thực nhiều yếu tố TOTP

Phần này mô tả cách xử lý việc người dùng huỷ đăng ký TOTP MFA.

Nếu người dùng đã đăng ký nhiều phương thức xác thực đa yếu tố và nếu họ huỷ đăng ký phương thức được bật gần đây nhất, thì họ sẽ nhận được auth/user-token-expired và bị đăng xuất. Người dùng phải đăng nhập lại và xác minh thông tin đăng nhập hiện có của họ, chẳng hạn như địa chỉ email và mật khẩu.

Để huỷ đăng ký người dùng, xử lý lỗi và kích hoạt xác thực lại, hãy sử dụng mã sau:

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

Bước tiếp theo