我已经设法通过GRPC使用流媒体模式的服务帐户为我的Android应用程序运行Google Cloud Speech。但是,根据我所读到的内容,出于安全原因,我不应该在其中部署具有这些凭据的Android应用程序(当前存储为资源中的JSON文件)。正确的做法是创建API密钥,如下所述:https://cloud.google.com/speech/docs/common/auth
这允许我限制对我的特定Android应用的访问。但是,我一直无法找到如何使用GRPC的API密钥。我目前正在从JSON文件创建一个GoogleCredentials
实例,这很好用。如何从API密钥获取凭证对象?
答案 0 :(得分:7)
您可以使用API密钥
进行尝试final ManagedChannel channel = new OkHttpChannelProvider()
.builderForAddress(HOSTNAME, PORT)
.nameResolverFactory(new DnsNameResolverProvider())
.intercept(new Interceptor(API_KEY))
.build();
speechStub = SpeechGrpc.newStub(channel);
private static final class Interceptor implements ClientInterceptor {
private final String apiKey;
private static Metadata.Key<String> API_KEY_HEADER =
Metadata.Key.of("x-goog-api-key", Metadata.ASCII_STRING_MARSHALLER);
public Interceptor(String apiKey) {
this.apiKey = apiKey;
}
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);
call = new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
if (apiKey != null && !apiKey.isEmpty()) {
headers.put(API_KEY_HEADER, apiKey);
}
super.start(responseListener, headers);
}
};
return call;
}
}
答案 1 :(得分:1)
我找不到任何Android示例。但是,示例iOS客户端使用API密钥设置gRPC连接。它将密钥放在请求标头中。您可以尝试将iOS代码翻译成Android。
答案 2 :(得分:0)
获得访问令牌后,您可以使用此方法:
final GoogleCredentials googleCredentials = new GoogleCredentials(accessToken) {
@Override
public AccessToken refreshAccessToken() throws IOException {
return accessToken;
}
}.createScoped(OAUTH2_SCOPES);
您需要覆盖refreshAccessToken()
,因为它目前不受支持。
答案 3 :(得分: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)
}