Google Cloud Platform - 云函数 API - 401 未经授权

2024-02-13

我正在努力使用 Java 通过 REST API 调用 GCP 云功能。

我为此执行的步骤是:

  • 创建角色为“Cloud Functions Invoker”的服务帐户
  • 下载新创建的服务帐户的 JSON 密钥文件
  • 在我的代码中,使用以下方法获取访问令牌:
private String getAuthToken() {
  File credentialsPath = new File(PATH_TO_JSON_KEY_FILE);

  GoogleCredentials credentials;
  try (FileInputStream serviceAccountStream = new FileInputStream(credentialsPath)) {
    credentials = ServiceAccountCredentials.fromStream(serviceAccountStream);
    return credentials
           .createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"))
           .refreshAccessToken()
           .getTokenValue();
  } catch (IOException e) {
    throw new RuntimeException("Action could not be performed");
  }
}
  • 使用创建的令牌执行 REST 调用:
public <Payload, Response> ResponseEntity<Response> callCloudFunction(
    String endpoint,
    Payload payload,
    Class<Response> klazz
) {
  RestTemplate restTemplate = new RestTemplate();
  HttpHeaders headers = new HttpHeaders();
  headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
  headers.setContentType(MediaType.APPLICATION_JSON);
  String url = gCloudUrl + endpoint;
  String token = getAuthToken();
  String payloadString = null;

  if (payload != null) {
    try {
      ObjectMapper objectMapper = new ObjectMapper();
      payloadString = objectMapper.writeValueAsString(payload);
    } catch (JsonProcessingException e) {
      System.out.println(e.getMessage());
      throw new RuntimeException("Could not perform action");
    }
  }

  headers.add("Authorization", String.format("Bearer %s", token));
  HttpEntity<String> entity = new HttpEntity<>(payloadString, headers);

  return restTemplate.exchange(url, HttpMethod.POST, entity, klazz);
}

实现看起来不错,但作为响应我收到 401 Unauthorized。

不幸的是,GCP 文档并没有多大帮助。我想我已经搜索过所有可能的地方了。


首先同意一下,目前还不清楚……

然后,您必须知道(并且再次不清楚)您需要访问令牌来调用 Google Cloud API,但需要身份令牌来调用 IAP(例如在 App Engine 上)或私有 Cloud Function 和 Cloud Run。而这个身份令牌需要经过谷歌的签名。

而且,正如代码中提到的,您需要在计算机上有一个服务帐户,但我建议您在 GCP 上避免这种情况,如果您使用默认身份验证,则不需要(请参阅我的代码,在您的计算机上设置GOOGLE_APPLICATION_CREDENTIALSenv var 指向服务帐户密钥文件)。最好的方法是不在您的计算机上使用服务帐户密钥文件,但这还不可能(IMO 这是一个安全问题,我正在与 Google 讨论这个问题......)

无论如何,这里有一个可以在 Java 中运行的代码片段(文档中没有任何地方......)

  String myUri = "https://path/to/url";
  // You can use here your service account key file. But, on GCP you don't require a service account key file.
  // However, on your computer, you require one because you need and identity token and you can generate it with your user account (long story... I'm still in discussion with Google about this point...)
  Credentials credentials = GoogleCredentials.getApplicationDefault().createScoped("https://www.googleapis.com/auth/cloud-platform");
  IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
    .setIdTokenProvider((IdTokenProvider) 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)));

NOTE如果您想继续使用 RestTemplate 对象并手动设置您的令牌,您可以像这样生成它

  String token = ((IdTokenProvider) credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
  System.out.println(token);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Google Cloud Platform - 云函数 API - 401 未经授权 的相关文章

随机推荐