【问题标题】:Authenticating Google Cloud Speech via GRPC on Android using an API key使用 API 密钥在 Android 上通过 GRPC 对 Google Cloud Speech 进行身份验证
【发布时间】:2016-10-15 15:07:44
【问题描述】:

我已经设法通过 GRPC 使用流模式下的服务帐户让 Google Cloud Speech 为我的 Android 应用程序工作。但是,根据我所阅读的内容,出于安全原因,我不应该在其中部署带有这些凭据的 Android 应用程序(当前存储为资源中的 JSON 文件)。正确的做法是创建一个 API 密钥,如下所述:https://cloud.google.com/speech/docs/common/auth

这允许我限制对我的特定 Android 应用的访问。但是,我一直无法从 GRPC 中找到如何使用 API 密钥。我目前正在从 JSON 文件创建一个 GoogleCredentials 实例,这工作正常。如何从 API 密钥中获取凭据对象?

【问题讨论】:

    标签: android google-cloud-speech


    【解决方案1】:

    您可以使用 API 密钥尝试此操作

    Metadata.Key<String> API_KEY = Metadata.Key.of("x-goog-api-key", Metadata.ASCII_STRING_MARSHALLER);
    
    Metadata apiKeyMetadata = new Metadata();
    apiKeyMetadata.put(API_KEY, yourApiKey);
    
    final ManagedChannel channel = new OkHttpChannelProvider()
        .builderForAddress(HOSTNAME, PORT)
        .nameResolverFactory(new DnsNameResolverProvider())
        .intercept(MetadataUtils.newAttachHeadersInterceptor(apiKeyMetadata))
        .build();
    speechStub = SpeechGrpc.newStub(channel);
    

    【讨论】:

    • 应用了这个,得到 android io.grpc.StatusRuntimeException: PERMISSION_DENIED: 来自这个 Android 客户端应用程序 的请求被阻止。,是否有应用程序包的标头?
    • 发现解决方案需要添加 X-Android-Package 和 X-Android-Cert 需要添加。
    • 很好奇,您在标头的元数据中为 X-Android-Cert 使用的值是多少?我可以得到 android 包名。但不确定前证书?
    【解决方案2】:

    我找不到任何 Android 示例。但是,示例 iOS 客户端使用 API 密钥设置 gRPC 连接。它将密钥放在请求标头中。您可以尝试将 iOS 代码翻译成 Android。

    https://github.com/GoogleCloudPlatform/ios-docs-samples/blob/master/speech/Objective-C/Speech-gRPC-Streaming/Speech/SpeechRecognitionService.m#L59

    【讨论】:

      【解决方案3】:

      获得访问令牌后,您可以使用此方法:

              final GoogleCredentials googleCredentials = new GoogleCredentials(accessToken) {
                  @Override
                  public AccessToken refreshAccessToken() throws IOException {
                      return accessToken;
                  }
              }.createScoped(OAUTH2_SCOPES);
      

      您需要覆盖 refreshAccessToken(),因为它目前不受支持。

      【讨论】:

        【解决方案4】:

        这是在 Kotlin 中执行此操作的方法。包括如何为受限密钥传递包和签名。

            private fun signatureDigest(sig: android.content.pm.Signature): String? {
        
                val signature: ByteArray = sig.toByteArray()
        
                return try {
                    val md: MessageDigest = MessageDigest.getInstance("SHA1")
                    val digest: ByteArray = md.digest(signature)
                    BaseEncoding.base16().lowerCase().encode(digest)
                } catch (e: NoSuchAlgorithmException) {
                    null
                }
            }
        
            fun getSignature(pm: PackageManager, packageName: String?): String? {
                return try {
                    val packageInfo: PackageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
                    if (packageInfo == null || packageInfo.signatures == null || packageInfo.signatures.size === 0 || packageInfo.signatures.get(0) == null) {
                        null
                    } else signatureDigest(packageInfo.signatures.get(0))
                } catch (e: PackageManager.NameNotFoundException) {
                    null
                }
            }
        
            private fun createConnection() {
        
                val packageName: String = mActivity.packageName
                val signature = getSignature(mActivity.packageManager, packageName)
        
                val API_KEY = Metadata.Key.of("X-Goog-Api-Key", Metadata.ASCII_STRING_MARSHALLER)
                val BUNDLE = Metadata.Key.of("X-Android-Package", Metadata.ASCII_STRING_MARSHALLER)
                val SIGN = Metadata.Key.of("X-Android-Cert", Metadata.ASCII_STRING_MARSHALLER)
        
                val apiKeyMetadata = Metadata()
                apiKeyMetadata.put(API_KEY, "YOUR_API_KEY")
                apiKeyMetadata.put(BUNDLE, packageName)
                apiKeyMetadata.put(SIGN, signature)
        
                val channel = OkHttpChannelProvider()
                        .builderForAddress(HOSTNAME, PORT)
                        .nameResolverFactory(DnsNameResolverProvider())
                        .intercept(MetadataUtils.newAttachHeadersInterceptor(apiKeyMetadata))
                        .build()
                mApi = SpeechGrpc.newStub(channel)
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-10-30
          • 1970-01-01
          • 2019-02-17
          • 1970-01-01
          • 1970-01-01
          • 2019-08-12
          • 1970-01-01
          • 2018-12-29
          相关资源
          最近更新 更多