4

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

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

4

4 回答 4

8

您可以使用 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);
于 2017-07-03T11:07:28.247 回答
1

我找不到任何 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

于 2016-12-04T06:36:52.393 回答
0

这是在 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)
    }
于 2020-05-05T12:44:07.830 回答
0

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

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

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

于 2016-10-16T16:24:04.300 回答