从 java 调用 Google 云 运行
Invoke a Google Cloud Run from java
我想从外部应用程序调用云 运行。外部应用程序是用 Kotlin (java) 和 运行 在 JDK 11 JVM 上编写的。它使用服务帐户进行身份验证
ServiceAccountCredentials.fromStream(serviceAccount).createScoped("https://www.googleapis.com/auth/cloud-platform")
服务帐户所在的位置是一个有效的 JSON 文件。我已经测试了在 google 云控制台中为服务帐户调用云 运行 的权限。
我还没有找到官方 API 所以我使用 google 的 GoogleNetHttpTransport 来 运行 一个 HTTP post 请求。
要调用云 运行 我尝试使用 HttpCredentialsAdapter
transport.createRequestFactory(HttpCredentialsAdapter(googleCredentials))
.buildPostRequest(GenericUrl(url), JsonHttpContent(JacksonFactory(), data))
我尝试使用访问令牌目录
val headers = HttpHeaders()
googleCredentials.refreshIfExpired()
headers.authorization = "Bearer " + googleCredentials.accessToken.tokenValue
postRequest.headers = headers
而且我尝试使用 jet 服务帐户并使用 jwt 请求元数据
val headers = HttpHeaders()
jwtCredentials = ServiceAccountJwtAccessCredentials.fromStream(serviceAccount)
jwtCredentials.getRequestMetadata(URI(url)).forEach {
headers.set(it.key, it.value)
}
postRequest.headers = headers
在所有这些情况下,它 returns 这个错误
[20:35:00 WARN]: Exception in thread "TestThread" com.google.api.client.http.HttpResponseException: 401 Unauthorized
[20:35:00 WARN]: at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
[20:35:00 WARN]: at ***.CloudRun$invoke.invokeSuspend(CloudRun.kt:34)
[20:35:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[20:35:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[20:35:00 WARN]: at java.base/java.lang.Thread.run(Thread.java:834)
提前感谢您的支持
我不太了解 Java SDK,但我想我发现了错误:
headers.authorization = "Bearer " + googleCredentials.accessToken.tokenValue
^^^^^^^^^^^
您不应将 GCP "access token" 发送到云 运行 应用程序(例如 https://*.run.app
)。该令牌用于调用 Google 的 API;和云 运行 应用程序不是那样。
相反,您应该发送一个 "identity token",这基本上表明您拥有该服务帐户,而不向被调用的服务授予任何权限(使用该令牌调用 GCP API) .
您无法在本地签署 "identity token",您需要调用端点。
我花时间在 OAuth2 Java 库上,问题如下。 classServiceAccountCredentials
加一个AccessToken
授权,classServiceAccountJwtAccessCredentials
加一个self-signed identity token
.
我将深入探讨,但现在您可以手动设置 header
String myUri = "https://.....";
Credentials credentials = ServiceAccountCredentials
.fromStream(resourceLoader.getResource("classpath:./key.json")
.getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");
String token = ((IdTokenProvider)credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory();
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization","Bearer " + token);
request.setHeaders(headers);
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
零件在这里,但不能一起工作。
编辑
在 GitHub 上进行了一些交流后,Google 为我提供了解决方案。现在 header 自动配置了一个签名的 id Token
Credentials credentials = ServiceAccountCredentials
.fromStream(resourceLoader.getResource("classpath:./key.json")
.getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");
IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
.setIdTokenProvider((ServiceAccountCredentials)credentials)
.setTargetAudience(myUri).build();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(idTokenCredentials));
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
我想从外部应用程序调用云 运行。外部应用程序是用 Kotlin (java) 和 运行 在 JDK 11 JVM 上编写的。它使用服务帐户进行身份验证
ServiceAccountCredentials.fromStream(serviceAccount).createScoped("https://www.googleapis.com/auth/cloud-platform")
服务帐户所在的位置是一个有效的 JSON 文件。我已经测试了在 google 云控制台中为服务帐户调用云 运行 的权限。
我还没有找到官方 API 所以我使用 google 的 GoogleNetHttpTransport 来 运行 一个 HTTP post 请求。 要调用云 运行 我尝试使用 HttpCredentialsAdapter
transport.createRequestFactory(HttpCredentialsAdapter(googleCredentials))
.buildPostRequest(GenericUrl(url), JsonHttpContent(JacksonFactory(), data))
我尝试使用访问令牌目录
val headers = HttpHeaders()
googleCredentials.refreshIfExpired()
headers.authorization = "Bearer " + googleCredentials.accessToken.tokenValue
postRequest.headers = headers
而且我尝试使用 jet 服务帐户并使用 jwt 请求元数据
val headers = HttpHeaders()
jwtCredentials = ServiceAccountJwtAccessCredentials.fromStream(serviceAccount)
jwtCredentials.getRequestMetadata(URI(url)).forEach {
headers.set(it.key, it.value)
}
postRequest.headers = headers
在所有这些情况下,它 returns 这个错误
[20:35:00 WARN]: Exception in thread "TestThread" com.google.api.client.http.HttpResponseException: 401 Unauthorized
[20:35:00 WARN]: at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
[20:35:00 WARN]: at ***.CloudRun$invoke.invokeSuspend(CloudRun.kt:34)
[20:35:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[20:35:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[20:35:00 WARN]: at java.base/java.lang.Thread.run(Thread.java:834)
提前感谢您的支持
我不太了解 Java SDK,但我想我发现了错误:
headers.authorization = "Bearer " + googleCredentials.accessToken.tokenValue
^^^^^^^^^^^
您不应将 GCP "access token" 发送到云 运行 应用程序(例如 https://*.run.app
)。该令牌用于调用 Google 的 API;和云 运行 应用程序不是那样。
相反,您应该发送一个 "identity token",这基本上表明您拥有该服务帐户,而不向被调用的服务授予任何权限(使用该令牌调用 GCP API) .
您无法在本地签署 "identity token",您需要调用端点。
我花时间在 OAuth2 Java 库上,问题如下。 classServiceAccountCredentials
加一个AccessToken
授权,classServiceAccountJwtAccessCredentials
加一个self-signed identity token
.
我将深入探讨,但现在您可以手动设置 header
String myUri = "https://.....";
Credentials credentials = ServiceAccountCredentials
.fromStream(resourceLoader.getResource("classpath:./key.json")
.getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");
String token = ((IdTokenProvider)credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory();
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization","Bearer " + token);
request.setHeaders(headers);
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
零件在这里,但不能一起工作。
编辑
在 GitHub 上进行了一些交流后,Google 为我提供了解决方案。现在 header 自动配置了一个签名的 id Token
Credentials credentials = ServiceAccountCredentials
.fromStream(resourceLoader.getResource("classpath:./key.json")
.getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");
IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
.setIdTokenProvider((ServiceAccountCredentials)credentials)
.setTargetAudience(myUri).build();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(idTokenCredentials));
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));