![](/img/trans.png)
[英]com.google.cloud.storage.StorageException: 401 Unauthorized
[英]Google Cloud Platform - cloud functions API - 401 Unauthorized
我正在努力通過 REST API 使用 Java 調用 GCP 雲功能。
我執行的步驟是:
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");
}
}
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.