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

1. 소개

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

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

" 단계별 버전 업데이트 릴리스"에 설명된 대로 Apple의 App Store Connect 기능을 사용하여 앱 업데이트를 점진적으로 릴리스하는 기능을 사용하면 앱 체크 출시가 더욱 원활하게 이루어질 수 있습니다. 이것은 간단하고 간단한 솔루션입니다. 그러나 앱 버전 업데이트를 단계적으로 출시해도 새 앱 버전을 게시하지 않고는 업데이트된 기존 앱의 출시를 제어하거나 동작을 변경할 수 없습니다.

App Attest 출시를 통해 앱 체크를 더 효과적으로 제어할 수 있는 한 가지 방법은 Firebase 원격 구성을 사용하여 한 번에 일정 비율의 앱 사용자에 대해 App Attest를 통한 앱 체크를 활성화하는 것입니다. 이는 증명 서버의 제한을 방지하는 데 도움이 될 수 있습니다. Google Analytics를 사용하여 출시가 사용자에게 미치는 영향을 관찰할 수 있습니다.

무엇을 배울 것인가

이 다단계 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 Analytics를 볼 수 있는 권한을 통해 앱과 연결된 Firebase 프로젝트에 액세스할 수 있습니다.

2. 사용자 정의 증명 공급자 만들기

이 단계에서는 App Attest가 활성화된 경우에만 토큰을 제공하는 사용자 지정 공급자 클래스를 만듭니다. 원격 구성은 구성된 Firebase 앱 인스턴스를 사용하며, 이 단계에서 구현하는 맞춤 제공자는 구성을 완료하기 위한 자리표시자 역할을 합니다.

다음 단계를 완료하려면 Xcode 앱의 프레임워크, 라이브러리 및 삽입된 콘텐츠 섹션Firebase , FirebaseRemoteConfigFirebaseAnalytics 추가해야 합니다. 이를 수행하는 방법에 대한 예는 Apple 플랫폼 Codelab용 Firebase 앱 검사를 참조하세요.

  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 공급자에게 전달합니다.

Analytics 이벤트 추가

Analytics 이벤트를 추가하면 앱 체크 출시의 성공 여부에 대한 더 나은 통찰력을 얻을 수 있습니다. 분석은 더 많은 대상을 대상으로 App Attest를 활성화해야 하는지 결정하는 데 도움이 됩니다.

두 가지 분석 이벤트(성공 시 AppAttestSuccess , 실패 시 AppAttestFailure) 를 기록합니다. 이 두 가지 Analytics 이벤트는 앱 체크 출시의 성공을 추적하고 대규모 출시를 진행해야 하는지 결정하는 데 도움이 될 수 있습니다.

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 제공자에게 토큰 요청을 전달하는 로직을 구현하고 일부 Analytics 이벤트를 추가한 후에는 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 콘솔에 원격 구성 매개변수 추가

이제 원격 구성 매개변수인 AppAttestEnabled를 Firebase 콘솔에 추가하겠습니다. getToken 메소드에는 이 매개변수가 필요합니다.

Firebase 콘솔에서 원격 구성 매개변수를 만들려면 다음 안내를 따르세요.

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

Firebase 콘솔에서 원격 구성 매개변수 생성

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

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

Firebase 콘솔에서 원격 구성 조건 정의

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

  1. 방금 생성한 조건에 대해 값을 true 로 설정합니다.
  2. 저장 을 클릭합니다.

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

완료되면 원격 구성 변경사항을 게시하세요.

기기에서 출시 테스트

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

마지막 단계는 Google Analytics를 사용하여 App Attest 출시의 성공 여부를 모니터링하는 것입니다.

5. AppCheck 출시 성공 여부를 검토하세요.

Analytics 이벤트 대시보드에서 출시 성공 여부를 측정할 수 있습니다. AppAttestSuccessAppAttestFailure 이벤트를 살펴보세요. 대시보드에 이벤트가 표시되는 데 최대 24시간이 걸릴 수 있습니다. 또는 디버깅을 활성화하고 DebugView를 사용하여 디버그 이벤트를 더 빠르게 볼 수 있습니다.

선택적으로 Crashlytics 대시보드에서 충돌 발생률의 증가를 모니터링할 수 있습니다. 앱에 Crashlytics를 추가하는 방법에 대한 자세한 내용은 Firebase Crashlytics 시작하기를 참조하세요.

대부분 AppAttestSuccess 이벤트가 표시되고 AppAttestFailure 이벤트는 거의 표시되지 않으면 원격 구성 매개변수 AppAttestEnabled 의 조건을 수정하여 App Attest를 활성화한 사용자의 비율을 늘릴 수 있다는 좋은 신호입니다.

Firebase 콘솔에서 Analytics 이벤트 검토

선택사항: Google Analytics 잠재고객 활용

AppAttestEnabled Analytics 이벤트를 더 활용하려면 Analytics Audience를 생성하여 AppAttestEnabled가 true로 설정된 사용자를 추적할 수 있습니다.

App Attest는 iOS 14.0과 함께 출시되었습니다. 일부 사용자는 이 릴리스에 포함되어 있지 않아 App Attest를 사용할 수 없습니다. 다른 Analytics 이벤트를 기록하여 이러한 사용자를 추적한 다음 DeviceCheck 와 같은 다른 증명 방법에 대해 해당 대상을 타겟팅할 수 있습니다.

선택사항: Crashlytics를 사용하여 충돌 모니터링

출시 중 앱의 안정성을 더 잘 이해하려면 Firebase Crashlytics를 사용하여 충돌 및 치명적이지 않은 상황을 모니터링하세요.

6. 축하합니다!

원격 구성을 사용하여 앱 체크를 성공적으로 출시했습니다 🎉

추가 리소스: