Firebase 원격 구성을 사용하여 Firebase 앱 체크를 점진적으로 출시

1. 소개

App Attest와 함께 Firebase 앱 체크를 사용하여 백엔드 서비스를 보호하고 Firebase 서비스에 대한 요청이 인증된 앱에서 오는지 확인할 수 있습니다.

일반적으로 할당량 한도에 도달하지 않도록 사용자를 App Attest 서비스에 점진적으로 온보딩하는 것이 좋습니다. 자세한 내용은 Apple의 'App Attest 서비스 사용 준비' 문서를 참조하세요.

'단계적 버전 업데이트 출시'에 설명된 대로 Apple의 App Store Connect 기능을 사용하여 점진적으로 앱 업데이트를 출시하는 기능을 사용하면 앱 체크 출시를 더 원활하게 할 수 있습니다. 이 방법은 간단하고 간단합니다. 하지만 앱 버전 업데이트를 단계별로 출시해도 새로운 앱 버전을 게시하지 않고는 기존에 업데이트된 앱의 출시를 제어하거나 동작을 변경할 수 없습니다.

App Attest 출시로 앱 체크를 더 세부적으로 관리하는 한 가지 방법은 Firebase 원격 구성을 사용하여 일정 비율의 앱 사용자에 대해 App Attest로 앱 체크를 사용 설정하는 것입니다. 이렇게 하면 증명 서버 제한을 방지할 수 있습니다. Google 애널리틱스를 사용하여 출시가 사용자에게 미치는 영향을 관찰할 수 있습니다.

학습 내용

이 다단계 Codelab에서는 Firebase 원격 구성을 사용하여 앱에 앱 체크를 출시하는 방법을 알아봅니다.

이 Codelab에서는 Apple 플랫폼용 Firebase 앱 체크 Codelab에 설명된 대로 DatabaseExample 빠른 시작 앱을 기반으로 하고 Firebase 앱 체크와 통합된 Firebase 프로젝트를 사용합니다. DatabaseExample 빠른 시작 앱을 통해 사용자는 Firebase 실시간 데이터베이스의 기능을 사용하여 로그인하고 게시물을 추가할 수 있습니다.

이 Codelab의 단계를 조정하여 자체 앱을 테스트할 수도 있습니다.

기본 요건

필요한 항목

  • Xcode 12.5 이상
  • App Attest 테스트:
    • 새 앱 식별자를 만들 수 있는 Apple 개발자 계정
    • App Attest 기능이 사용 설정된 명시적인 앱 ID가 있는 애플리케이션 이 과정에서 도움이 필요하면 앱 ID 등록앱 기능 사용 설정 도움말을 참고하세요.
    • App Attest를 지원하는 iOS/iPadOS 기기
  • 다음이 포함된 Firebase 프로젝트:
  • 원격 구성을 만들고 관리할 수 있는 권한과 Google 애널리틱스를 볼 수 있는 권한이 포함된 앱의 연결된 Firebase 프로젝트에 대한 액세스 권한입니다.

2. 커스텀 증명 제공업체 만들기

이 단계에서는 App Attest가 사용 설정된 경우에만 토큰을 제공하는 커스텀 제공자 클래스를 만듭니다. 원격 구성은 구성된 Firebase 앱 인스턴스에 의존하며 이 단계에서 구현하는 커스텀 제공업체는 구성을 완료하는 자리표시자 역할을 합니다.

다음 단계를 완료하려면 Xcode에서 앱의 프레임워크, 라이브러리 및 삽입된 콘텐츠 섹션Firebase, FirebaseRemoteConfig, FirebaseAnalytics를 추가해야 합니다. 이 작업을 실행하는 방법의 예는 Apple 플랫폼용 Firebase 앱 체크 Codelab을 참고하세요.

  1. AppCheckProvider 프로토콜을 준수하는 NSObject의 서브클래스인 'MyAppCheckProvider' 파일을 만듭니다.
  2. 나중에 작성할 빈 getToken() 메서드를 포함합니다.

getToken() 메서드가 있는 커스텀 제공자 클래스에 관한 다음 예시 코드를 참고하세요.

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {}
}

AppAttestProvider를 인스턴스화하려면 상응하는 FirebaseApp의 인스턴스를 전달해야 합니다. 저장된 속성을 만들고 이를 이니셜라이저 매개변수로 허용합니다.

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  // Firebase app instance served by the provider.
  let firebaseApp: FirebaseApp

  // The App Check provider factory should pass the FirebaseApp instance.
  init(app: FirebaseApp) {
    self.firebaseApp = app
    super.init()
  }

  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {}
}

App Attest 제공업체에 토큰 요청 전달

이제 getToken() 메서드의 토큰 요청을 App Attest 제공자로 전달하기 위한 모든 준비를 마쳤습니다.

참고: FirebaseAppCheck 프레임워크 참조에서 getToken() 메서드에 대해 자세히 알아보세요.

다음 코드를 getToken() 메서드에 추가합니다.

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  // Firebase app instance served by the provider.
  let firebaseApp: FirebaseApp

  // The App Check provider factory should pass the FirebaseApp instance.
  init(app: FirebaseApp) {
    self.firebaseApp = app
    super.init()
  }

  private lazy var appAttestProvider = AppAttestProvider(app: firebaseApp)

  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {
    // Fetch App Attest flag from Remote Config
    let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp)
    remoteConfig.fetchAndActivate { remoteConfigStatus, error in
      // Get App Attest flag value
      let appAttestEnabled = remoteConfig.configValue(forKey: "AppAttestEnabled").boolValue

      guard appAttestEnabled else {
        // Skip attestation if App Attest is disabled. Another attestation
        // method like DeviceCheck may be used instead of just skipping.
        handler(nil, MyProviderError.appAttestIsDisabled)
        return
      }

      // Try to obtain an App Attest provider instance and fail if cannot
      guard let appAttestProvider = self.appAttestProvider else {
        handler(nil, MyProviderError.appAttestIsUnavailable)
        return
      }

      // If App Attest is enabled for the app instance, then forward the
      // Firebase App Check token request to the App Attest provider
      appAttestProvider.getToken(completion: handler)
    }
  }
}

enum MyProviderError: Error {
  case appAttestIsDisabled
  case appAttestIsUnavailable
  case unexpected(code: Int)
}

이전 코드는 원격 구성 AppAttestEnabled 부울 매개변수를 확인합니다. 이 원격 구성 매개변수는 Codelab에서 나중에 만듭니다. 값이 false이면 코드가 실패하여 앱 체크가 현재 기기에서 롤아웃되지 않았음을 나타냅니다. 값이 true인 경우 코드는 App Attest 제공자를 가져오려고 시도하지만 가져올 수 없는 경우 실패합니다. 이러한 오류 검사를 통과하면 코드는 토큰 요청을 App Attest 제공자로 전달합니다.

애널리틱스 이벤트 추가

애널리틱스 이벤트를 추가하면 앱 체크 출시가 얼마나 성공했는지에 대한 유용한 정보를 얻을 수 있습니다. 애널리틱스를 사용하면 더 많은 잠재고객을 대상으로 App Attest를 사용 설정해야 하는지 여부를 판단하는 데 도움이 됩니다.

애널리틱스 이벤트 2개(성공 시 AppAttestSuccess, 실패 시 AppAttestFailure)를 로깅합니다. 이 두 가지 애널리틱스 이벤트는 앱 체크 출시의 성공을 추적하고 대규모 출시를 진행할지 결정하는 데 도움이 됩니다.

func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {
  // Fetch Remote Config.
  let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp)
  remoteConfig.fetchAndActivate { remoteConfigStatus, error in
    // Get App Attest flag value from Remote Config.
    let appAttestEnabled = remoteConfig.configValue(forKey: "AppAttestEnabled").boolValue

    guard appAttestEnabled else {
      // Skip attestation if App Attest is disabled. Another attestation
      // method like DeviceCheck may be used instead of just skipping.
      handler(nil, MyProviderError.appAttestIsDisabled)
      return
    }

    // Try to obtain an App Attest provider instance and fail otherwise.
    guard let appAttestProvider = self.appAttestProvider else {
      handler(nil, MyProviderError.appAttestIsUnavailable)
      return
    }

    // If App Attest is enabled for the app instance, then forward the
    // Firebase App Check token request to the App Attest provider.
    appAttestProvider.getToken { token, error in
      // Log an Analytics event to track attestation success rate.
      let appAttestEvent: String
      if (token != nil && error == nil) {
        appAttestEvent = "AppAttestSuccess"
      } else {
        appAttestEvent = "AppAttestFailure"
      }
      Analytics.logEvent(appAttestEvent, parameters: nil)

      // Pass the result to the handler
      handler(token, error)
    }
  }
}

3. Provider Factory 클래스 업데이트

토큰 요청을 App Attest 제공자로 전달하는 로직을 구현하고 일부 애널리틱스 이벤트를 추가한 후에는 Apple 플랫폼용 앱 체크 Codelab에서 만든 MyAppCheckProviderFactory.class를 업데이트해야 합니다. 이 클래스는 시뮬레이터의 앱 체크 디버그 제공자를 타겟팅하고 그 외의 경우에는 맞춤 제공자를 타겟팅합니다.

Apple 플랫폼용 Firebase 앱 체크 Codelab에서 만든 MyAppCheckProviderFactory 클래스에서 다음 코드를 수정합니다.

// MyAppCheckProviderFactory.swift

import Firebase

class MyAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
  func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
      #if targetEnvironment(simulator)
      // App Attest is not available on simulators.
      // Use a debug provider.
      let provider = AppCheckDebugProvider(app: app)

      // Print only locally generated token to avoid a valid token leak on CI.
      print("Firebase App Check debug token: \(provider?.localDebugToken() ?? "" )")

      return provider
      #else
      if #available(iOS 14.0, *) {
        // Use your custom App Attest provider on real devices.
        return MyAppCheckProvider(app: app)
      } else {
        return DeviceCheckProvider(app: app)
      }
      #endif
  }
}

FirebaseApp를 구성하기 전에 AppCheckProviderFactory를 설정했는지 확인합니다.

// DatabaseExampleApp.swift

import SwiftUI
import Firebase
import FirebaseAppCheck

@main
struct DatabaseExampleApp: App {
  init() {
    AppCheck.setAppCheckProviderFactory(MyAppCheckProviderFactory())
    FirebaseApp.configure()
  }

  // ...
}

4. Firebase Console에서 원격 구성 매개변수 추가

이제 Firebase Console에 원격 구성 매개변수 AppAttestEnabled를 추가합니다 . getToken 메서드에는 이 매개변수가 필요합니다.

Firebase Console에서 원격 구성 매개변수를 만드는 방법은 다음과 같습니다.

  1. 프로젝트의 원격 구성을 열고 매개변수 추가를 클릭합니다. 원격 구성을 처음 사용하는 경우 구성 만들기를 클릭합니다.
  2. 매개변수 이름 (키) 필드에 AppAttestEnabled를 입력합니다.
  3. 데이터 유형 드롭다운에서 부울을 선택합니다.
  4. 기본값 드롭다운에서 false를 선택합니다.

Firebase Console에서 원격 구성 매개변수 만들기

저장을 클릭하기 전에 다음과 같이 사용자 10% 에 대한 조건부 값을 만듭니다.

  1. 새로 추가 > 조건부 값 > 새 조건 만들기를 클릭합니다.
  2. 이름 필드에 조건 이름을 입력합니다.
  3. 적용 조건...에서 임의 백분위수의 사용자, <=를 선택한 다음 % 필드에 10을 입력합니다.
  4. 조건 만들기를 클릭합니다.

Firebase Console에서 원격 구성 조건 정의

App Attest가 10% 의 사용자에게 배포되도록 조건부 값을 true로 설정합니다.

  1. 방금 만든 조건의 값을 true로 설정합니다.
  2. 저장을 클릭합니다.

Firebase Console에서 원격 구성 매개변수 검토

완료되면 원격 구성 변경사항을 게시합니다.

기기에서 출시 테스트하기

앱 코드를 수정하지 않고 기기에서 다양한 원격 구성 플래그 값을 테스트하려면 A/B 테스팅으로 Firebase 원격 구성 실험 만들기 튜토리얼에 따라 AppAttestEnabled 매개변수에 실험을 구성합니다. '테스트 기기에서 실험 검증' 튜토리얼 섹션에서는 테스트 기기에 다른 값을 할당하는 방법을 설명합니다.

마지막 단계는 Google 애널리틱스를 사용하여 App Attest 출시의 성공을 모니터링하는 것입니다.

5. AppCheck 출시 성공 검토

애널리틱스 이벤트 대시보드에서 출시 성공 여부를 측정할 수 있습니다. AppAttestSuccessAppAttestFailure 이벤트를 확인합니다. 대시보드에 이벤트가 표시되는 데 최대 24시간이 걸릴 수 있습니다. 또는 디버깅을 사용 설정하고 DebugView를 사용하여 디버그 이벤트를 더 빠르게 확인할 수 있습니다.

원하는 경우 Crashlytics 대시보드를 모니터링하여 비정상 종료 발생률이 증가하는지 모니터링할 수 있습니다. 앱에 Crashlytics를 추가하는 방법에 관한 자세한 내용은 Firebase Crashlytics 시작하기를 참고하세요.

대부분의 경우 AppAttestSuccess 이벤트가 표시되고 AppAttestFailure 이벤트는 거의 없는 것으로 나타나면 원격 구성 매개변수 AppAttestEnabled에서 조건을 수정하여 App Attest를 사용 설정한 사용자의 비율을 높일 수 있다는 좋은 신호입니다.

Firebase Console에서 애널리틱스 이벤트 검토

선택사항: Google 애널리틱스 잠재고객 활용

AppAttestEnabled 애널리틱스 이벤트를 더 활용하려면 애널리틱스 잠재고객을 만들어 AppAttestEnabled를 true로 설정한 사용자를 추적하면 됩니다.

App Attest는 iOS 14.0에서 출시되었습니다. 일부 사용자가 이 버전을 사용하지 않으므로 App Attest를 사용하지 못할 수 있습니다. 다른 애널리틱스 이벤트를 기록하여 이러한 사용자를 추적한 다음 DeviceCheck와 같은 다른 증명 방법으로 해당 잠재고객을 타겟팅할 수 있습니다.

선택사항: Crashlytics를 사용하여 비정상 종료 모니터링

출시 중 앱의 안정성을 더 잘 파악하려면 Firebase Crashlytics를 사용하여 비정상 종료 및 심각하지 않은 항목을 모니터링하세요.

6. 수고하셨습니다.

원격 구성으로 앱 체크를 출시했습니다. 🎉

추가 리소스: