4

问:如何解决 Firebase App Check 的权限错误?

背景:我已根据文档启用 App Check:

DeviceCheck 已启用/配置: https ://firebase.google.com/docs/app-check/ios/devicecheck-provider

App Attest 已启用配置: https ://firebase.google.com/docs/app-check/ios/devicecheck-provider

SDK 被添加到项目中,代码来自: https ://github.com/firebase/firebase-ios-sdk/blob/master/FirebaseAppCheck/Apps/FIRAppCheckTestApp/FIRAppCheckTestApp/AppDelegate.swift

具体来说,在 appdelegate: Token setup 中:

FirebaseApp.configure()

requestDeviceCheckToken()

requestDebugToken()

if #available(iOS 14.0, *) {
  requestAppAttestToken()
}

调用:

  // MARK: App Check providers
  func requestDeviceCheckToken() {
    guard let firebaseApp = FirebaseApp.app() else {
      return
    }

    DeviceCheckProvider(app: firebaseApp)?.getToken { token, error in
      if let token = token {
        print("DeviceCheck token: \(token.token), expiration date: \(token.expirationDate)")
      }

      if let error = error {
        print("DeviceCheck error: \((error as NSError).userInfo)")
      }
    }
  }

  func requestDebugToken() {
    guard let firebaseApp = FirebaseApp.app() else {
      return
    }

    if let debugProvider = AppCheckDebugProvider(app: firebaseApp) {
      print("Debug token: \(debugProvider.currentDebugToken())")

      debugProvider.getToken { token, error in
        if let token = token {
          print("Debug FAC token: \(token.token), expiration date: \(token.expirationDate)")
        }

        if let error = error {
          print("Debug error: \(error)")
        }
      }
    }
  }

  @available(iOS 14.0, *)
  func requestAppAttestToken() {
    guard let firebaseApp = FirebaseApp.app() else {
      return
    }

    guard let appAttestProvider = AppAttestProvider(app: firebaseApp) else {
      print("Failed to instantiate AppAttestProvider")
      return
    }

    appAttestProvider.getToken { token, error in
      if let token = token {
        print("App Attest FAC token: \(token.token), expiration date: \(token.expirationDate)")
      }

      if let error = error {
        print("App Attest error: \(error)")
      }
    }
  }

requestDeviceCheckToken() 返回权限错误:

DeviceCheck error: ["NSLocalizedFailureReason": The server responded with an error: 
 - URL: https://firebaseappcheck.googleapis.com/v1beta/projects/<GOOGLE_APP_ID>:exchangeDeviceCheckToken 
 - HTTP status code: 403 
 - Response body: {
  "error": {
    "code": 403,
    "message": "Requests from this iOS client application \u003cempty\u003e are blocked.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "API_KEY_IOS_APP_BLOCKED",
        "domain": "googleapis.com",
        "metadata": {
          "service": "firebaseappcheck.googleapis.com",
          "consumer": "projects/<my project #>"
        }
      }
    ]
  }
}

requestDebugToken() 返回权限错误:

Debug error: Error Domain=com.firebase.appCheck Code=0 "The server responded with an error: 
 - URL: https://firebaseappcheck.googleapis.com/v1beta/projects/<GOOGLE_APP_ID>:exchangeDebugToken 
 - HTTP status code: 403 
 - Response body: {
  "error": {
    "code": 403,
    "message": "Requests from this iOS client application \u003cempty\u003e are blocked.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "API_KEY_IOS_APP_BLOCKED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/<my project #>",
          "service": "firebaseappcheck.googleapis.com"
        }
      }
    ]
  }
}
" UserInfo={NSLocalizedFailureReason=The server responded with an error: 
 - URL: https://firebaseappcheck.googleapis.com/v1beta/projects/<GOOGLE_APP_ID>:exchangeDebugToken 
 - HTTP status code: 403 
 - Response body: {
  "error": {
    "code": 403,
    "message": "Requests from this iOS client application \u003cempty\u003e are blocked.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "API_KEY_IOS_APP_BLOCKED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/<my project #",
          "service": "firebaseappcheck.googleapis.com"
        }
      }
    ]
  }
}
}

requestAppAttestToken() 返回错误:

App Attest error: Error Domain=com.firebase.appCheck Code=0 "(null)"

GCP Console 确实显示了对以下 100% 错误的所有调用:

google.firebase.appcheck.v1beta.TokenExchangeService.ExchangeDebugToken 
    google.firebase.appcheck.v1beta.TokenExchangeService.ExchangeDeviceCheckToken   
    google.firebase.appcheck.v1beta.TokenExchangeService.GenerateAppAttestChallenge 

所有这些似乎都指向权限错误?具体来说,GOOGLE_APP_ID 在请求 URL 中,但 App Check 是通过控制台在 Firebase 中配置的......

我没有在文档中看到任何我错过的内容或在 IAM 中看到的任何明显内容?:(

提前Ty寻求帮助!

更新 与邮递员进一步测试后:

问题似乎是X-Ios-Bundle-Identifier调用 AppCheck API 时 SDK 未正确传递。

得出这个结论的步骤:

  • 来自 POSTMAN:API 调用 w/原始 API_KEY -> 产生初始(以上)错误响应/403
  • 来自 POSTMAN:API 调用如上,+ X-Ios-Bundle-Identifier + 有效 debug_token -> 产生成功负载。

所以:

  • 有什么想法可以帮助识别为什么X-Ios-Bundle-IdentifierSDK 没有通过?该应用程序正在使用其他 Firebase API 的无问题,因此似乎仅限于 AppCheck SDK...
  • 和/或 - 可以X-Ios-Bundle-Identifier以编程方式(在 Swift 中)添加到 AppCheck 调用中(它在 .plist 中正确标注)

解决!

App Check SDK 目前不支持 API 密钥的 Android / iOS 应用程序限制。这样,您必须删除 API 密钥的应用程序限制才能解决此问题。

希望在某个时候会支持应用程序限制...

更新!

v8.8.0-beta 现在支持捆绑 ID!:)

4

2 回答 2

2

1.配置DeviceCheck的私钥

  • 确保您已为 DeviceCheck 创建了私钥 在此处输入图像描述

  • 并将其安装在 AppCheck 选项卡下的 firebase 项目设置中 在此处输入图像描述

https://firebase.google.com/docs/app-check/ios/devicecheck-provider

2. 将调试令牌添加到 Firebase。

如果您使用 AppCheckDebugProvider(主要用于模拟器),运行项目后您会在控制台中看到一个调试令牌,您需要将其复制并添加到项目设置的 AppCheck 中。比 AppCheck 会批准它。也不要忘记添加-FIRDebugEnabled.Arguments Passed on Launch

https://firebase.google.com/docs/app-check/ios/debug-provider

3. 为 AppAttest 环境添加生产授权。

AppCheck 的测试版不适用于 AppAttest 开发环境,因此您需要production在您的权利中设置环境。默认情况下,AppAttest 在开发环境中工作,无论您在市场上做出何种选择,它都可以在生产环境中工作。

https://firebase.google.com/docs/app-check/ios/app-attest-provider

https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_devicecheck_appattest-environment

在此处输入图像描述

4. 可选:

您可以简化代码

#if targetEnvironment (simulator)
    let providerFactory = AppCheckDebugProviderFactory ()
#else
    let providerFactory = CustomAppCheckProviderFactory ()
#endif

AppCheck.setAppCheckProviderFactory (providerFactory)

并获得令牌

if let fbApp = FirebaseApp.app () {
    providerFactory.createProvider(with: fbApp)?.getToken { token, error in
        if let token = token {
            print ("AppCheck token: \ (token.token), expiration date: \ (token.expirationDate)")
        } else if let error = error {
            print ("AppCheck error: \ (error as NSError).userInfo)")
        }
    }
}

或者,如果您想保护非 Firebase 资源,您可以获得这样的令牌:

AppCheck.appCheck().token (forcingRefresh: false) { token, error in
    if let token = token {
        print ("AppCheck token: \ (token.token), expiration date: \ (token.expirationDate)")
    } else if let error = error {
        print ("AppCheck error: \ (error as NSError).userInfo)")
    }
}

https://firebase.google.com/docs/app-check/ios/custom-resource

于 2021-09-05T09:46:00.180 回答
2

App Check SDK 目前不支持 API 密钥的 Android / iOS 应用程序限制。这样,您必须删除 API 密钥的应用程序限制才能解决此问题。

希望在某个时候会支持应用程序限制...

于 2021-09-20T02:24:00.403 回答