Google Cloud Platform - API облачных функций - 401 Unauthorized - PullRequest
1 голос
/ 12 июля 2020

Я не могу вызвать облачные функции GCP через REST API, используя Java.

Для этого я выполнил следующие шаги:

  • создать службу учетная запись с ролью «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 бесполезна. Думаю, я перебрал все возможные места.

1 Ответ

3 голосов
/ 12 июля 2020

Во-первых, согласитесь, непонятно ...

Затем вы должны знать (и опять не ясно), что вам нужен токен доступа для вызова Google Cloud API, но и токен идентификации для вызова IAP (например, в App Engine) или функции частного облака и Cloud Run. И этот идентификационный токен должен быть подписан Google.

И, как указано в коде, вам необходимо иметь учетную запись службы на вашем компьютере, но я рекомендую вам избегать этого в GCP, это не требуется, если вы используете аутентификацию по умолчанию (см. мой код, на вашем компьютере установите переменную env GOOGLE_APPLICATION_CREDENTIALS, которая указывает на файл ключа учетной записи службы). Лучше всего не использовать ключевой файл служебной учетной записи на вашем компьютере, но это пока невозможно (это проблема безопасности, ИМО, и я обсуждаю это с 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 и вручную установить свой токен, вы можете сгенерировать его так:

  String token = ((IdTokenProvider) credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
  System.out.println(token);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...