Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从java调用Google云运行_Java_Google Cloud Run - Fatal编程技术网

从java调用Google云运行

从java调用Google云运行,java,google-cloud-run,Java,Google Cloud Run,我想从外部应用程序调用云运行。外部应用程序是用Kotlin(java)编写的,并在JDK 11 JVM上运行。它使用服务帐户进行身份验证 ServiceAccountCredentials.fromStream(serviceAccount).createScoped("https://www.googleapis.com/auth/cloud-platform") 其中服务帐户是一个有效的JSON文件。我已经测试了在谷歌云控制台中为服务帐户调用云运行的权限 我还没有找到一个官方的API,所以

我想从外部应用程序调用云运行。外部应用程序是用Kotlin(java)编写的,并在JDK 11 JVM上运行。它使用服务帐户进行身份验证

ServiceAccountCredentials.fromStream(serviceAccount).createScoped("https://www.googleapis.com/auth/cloud-platform")
其中服务帐户是一个有效的JSON文件。我已经测试了在谷歌云控制台中为服务帐户调用云运行的权限

我还没有找到一个官方的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
在所有这些情况下,它都会返回此错误

[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$3.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“访问令牌”(例如
https://*.Run.app
)。该令牌用于调用谷歌的API;而云计算应用程序并非如此

相反,您应该发送一个“身份令牌”,它基本上表明您拥有该服务帐户,而不向被调用的服务授予任何权限(使用该令牌调用GCP API)

您不能自己在本地签署“身份令牌”,您需要调用端点


本页对此进行了解释:

我花时间研究OAuth2Java库,问题如下。类
ServiceAccountCredentials
添加一个
AccessToken
作为授权,类
ServiceAccountJwtAccessCredentials
添加一个自签名的

我将更深入地讨论它,但现在您可以手动设置标题

        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上进行了一些交流之后,谷歌为我提供了解决方案。现在,头自动配置有签名的id令牌

        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)));

“调用云运行”是什么意思?Cloud Run是承载REST/HTTP应用程序的平台/环境。您创建了一个应用程序,该应用程序侦听$PORT并响应HTTP请求。您的意思是调用托管在容器中的自定义REST应用程序吗?如果是,该应用程序的性质是什么?我想向在云运行容器中运行的另一个REST应用程序发布请求。云运行用于各种任务,并且是用node js编写的。所以我想这基本上就是我所说的,但是你知道Java。:)@Gabber235我用Java内置模式更新了我的答案!不需要手动标题!