簡體   English   中英

Google Cloud Platform - 雲功能 API - 401 未經授權

[英]Google Cloud Platform - cloud functions API - 401 Unauthorized

我正在努力通過 REST API 使用 Java 調用 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 上)或私有雲 Function 和 Cloud Run。 而這個身份令牌需要谷歌簽名。

而且,如代碼中所述,您需要在您的計算機上擁有一個服務帳戶,但我建議您在 GCP 上避免這種情況,如果您使用默認身份驗證則不需要(請參閱我的代碼,在您的計算機上設置GOOGLE_APPLICATION_CREDENTIALS env 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)));

注意如果您想繼續使用 RestTemplate object 並手動設置您的令牌,您可以像這樣生成它

  String token = ((IdTokenProvider) credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
  System.out.println(token);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM