기존 번들 서비스용 App Identity API

리전 ID

REGION_ID는 앱을 만들 때 선택한 리전을 기준으로 Google에서 할당하는 축약된 코드입니다. 일부 리전 ID는 일반적으로 사용되는 국가 및 주/도 코드와 비슷하게 표시될 수 있지만 코드는 국가 또는 주/도와 일치하지 않습니다. 2020년 2월 이후에 생성된 앱의 경우 REGION_ID.r이 App Engine URL에 포함됩니다. 이 날짜 이전에 만든 기존 앱의 경우 URL에서 리전 ID는 선택사항입니다.

리전 ID에 대해 자세히 알아보세요.

App Identity API를 사용하면 애플리케이션이 스스로의 애플리케이션 ID(다른 명칭은 프로젝트 ID)를 확인할 수 있습니다. App Engine 애플리케이션은 이 ID를 사용하여 다른 App Engine 앱, Google API, 서드 파티 애플리케이션 및 서비스에 자신의 ID를 알릴 수 있습니다. 애플리케이션 ID는 URL 또는 이메일 주소를 생성하거나 런타임을 결정하는 데 사용될 수도 있습니다.

프로젝트 ID 가져오기

프로젝트 ID는 ApiProxy.getCurrentEnvironment().getAppId() 메서드를 사용하여 확인할 수 있습니다.

애플리케이션 호스트 이름 가져오기

기본적으로 App Engine 앱은 https://PROJECT_ID.REGION_ID.r.appspot.com 형식의 URL에서 제공되며, 여기서 프로젝트 ID는 호스트 이름의 일부입니다. 앱이 커스텀 도메인에서 제공될 때는 전체 호스트 이름 구성요소를 검색해야 할 수 있습니다. CurrentEnvironmentcom.google.appengine.runtime.default_version_hostname 속성을 사용하여 이 작업을 수행할 수 있습니다.

@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
  resp.setContentType("text/plain");
  ApiProxy.Environment env = ApiProxy.getCurrentEnvironment();
  resp.getWriter().print("default_version_hostname: ");
  resp.getWriter()
      .println(env.getAttributes().get("com.google.appengine.runtime.default_version_hostname"));
}

다른 App Engine 앱에 ID 알림

App Engine 앱에 요청하는 App Engine 앱의 ID를 확인하려면 요청 헤더 X-Appengine-Inbound-Appid를 사용하면 됩니다. 이 헤더는 URLFetch 서비스를 통해 요청에 추가되며 사용자가 수정할 수 없으므로 이 헤더가 있으면 요청하는 애플리케이션의 프로젝트 ID라고 신뢰할 수 있습니다.

요구사항:

  • 앱의 appspot.com 도메인에 대한 호출에만 X-Appengine-Inbound-Appid 헤더가 포함됩니다. 커스텀 도메인에 대한 호출은 헤더를 포함하지 않습니다.
  • 리디렉션을 따르지 않도록 요청을 설정해야 합니다. URLFetchService 클래스를 사용할 경우 앱은 doNotFollowRedirect를 지정해야 합니다. 자바 8 런타임에서 실행되는 앱은 기본적으로 URLFetch 서비스를 사용하지 않습니다. URLFetch를 사용 설정하려면 다음 안내를 따르세요.
  • 앱이 java.net을 사용할 경우 리디렉션을 따르지 않도록 코드를 업데이트합니다.
    connection.setInstanceFollowRedirects(false);

애플리케이션 핸들러에서 X-Appengine-Inbound-Appid 헤더를 읽고 요청을 실행할 수 있는 ID 목록과 비교하여 수신 ID를 확인할 수 있습니다.

Google API에 ID 알림

Google API는 인증 및 승인에 OAuth 2.0 프로토콜을 사용합니다. App Identity API는 요청 소스가 애플리케이션 자체라고 어설션하는 데 사용되는 OAuth 토큰을 만들 수 있습니다. getAccessToken() 메서드는 특정 범위 또는 범위 목록의 액세스 토큰을 반환합니다. 이 토큰을 호출의 HTTP 헤더에 설정하면 호출하는 애플리케이션을 식별할 수 있습니다.

다음 예시에서는 App Identity API를 사용하여 Google URL Shortener API에 REST 호출을 보내는 방법을 보여줍니다.

/**
 * Returns a shortened URL by calling the Google URL Shortener API.
 *
 * <p>Note: Error handling elided for simplicity.
 */
public String createShortUrl(String longUrl) throws Exception {
  ArrayList<String> scopes = new ArrayList<>();
  scopes.add("https://www.googleapis.com/auth/urlshortener");
  final AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService();
  final AppIdentityService.GetAccessTokenResult accessToken = appIdentity.getAccessToken(scopes);
  // The token asserts the identity reported by appIdentity.getServiceAccountName()
  JSONObject request = new JSONObject();
  request.put("longUrl", longUrl);

  URL url = new URL("https://www.googleapis.com/urlshortener/v1/url?pp=1");
  HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  connection.setDoOutput(true);
  connection.setRequestMethod("POST");
  connection.addRequestProperty("Content-Type", "application/json");
  connection.addRequestProperty("Authorization", "Bearer " + accessToken.getAccessToken());

  OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
  request.write(writer);
  writer.close();

  if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
    // Note: Should check the content-encoding.
    //       Any JSON parser can be used; this one is used for illustrative purposes.
    JSONTokener responseTokens = new JSONTokener(connection.getInputStream());
    JSONObject response = new JSONObject(responseTokens);
    return (String) response.get("id");
  } else {
    try (InputStream s = connection.getErrorStream();
        InputStreamReader r = new InputStreamReader(s, StandardCharsets.UTF_8)) {
      throw new RuntimeException(
          String.format(
              "got error (%d) response %s from %s",
              connection.getResponseCode(), CharStreams.toString(r), connection.toString()));
    }
  }
}

애플리케이션의 ID는 서비스 계정 이름(일반적으로 applicationid@appspot.gserviceaccount.com)으로 표시됩니다. getServiceAccountName() 메서드를 사용하면 정확한 값을 가져올 수 있습니다. ACL을 제공하는 서비스의 경우 이 계정 액세스 권한을 부여하여 애플리케이션 액세스 권한을 부여할 수 있습니다.

서드 파티 서비스에 ID 알림

getAccessToken()으로 생성된 토큰은 Google 서비스에서만 작동합니다. 그러나 내부적인 서명 기술을 사용하면 다른 서비스에 애플리케이션의 ID를 알릴 수 있습니다. signForApp() 메서드는 애플리케이션에 고유한 비공개 키를 사용하여 바이트에 서명하고 getPublicCertificatesForApp() 메서드는 서명을 검증하는 데 사용할 수 있는 인증서를 반환합니다.

다음 예에서는 BLOB에 서명하고 서명을 검증하는 방법을 보여줍니다.
// Note that the algorithm used by AppIdentity.signForApp() and
// getPublicCertificatesForApp() is "SHA256withRSA"

private byte[] signBlob(byte[] blob) {
  AppIdentityService.SigningResult result = appIdentity.signForApp(blob);
  return result.getSignature();
}

private byte[] getPublicCertificate() throws UnsupportedEncodingException {
  Collection<PublicCertificate> certs = appIdentity.getPublicCertificatesForApp();
  PublicCertificate publicCert = certs.iterator().next();
  return publicCert.getX509CertificateInPemFormat().getBytes("UTF-8");
}

private Certificate parsePublicCertificate(byte[] publicCert)
    throws CertificateException, NoSuchAlgorithmException {
  InputStream stream = new ByteArrayInputStream(publicCert);
  CertificateFactory cf = CertificateFactory.getInstance("X.509");
  return cf.generateCertificate(stream);
}

private boolean verifySignature(byte[] blob, byte[] blobSignature, PublicKey pk)
    throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
  Signature signature = Signature.getInstance("SHA256withRSA");
  signature.initVerify(pk);
  signature.update(blob);
  return signature.verify(blobSignature);
}

private String simulateIdentityAssertion()
    throws CertificateException, UnsupportedEncodingException, NoSuchAlgorithmException,
    InvalidKeyException, SignatureException {
  // Simulate the sending app.
  String message = "abcdefg " + Calendar.getInstance().getTime().toString();
  byte[] blob = message.getBytes();
  byte[] blobSignature = signBlob(blob);
  byte[] publicCert = getPublicCertificate();

  // Simulate the receiving app, which gets the certificate, blob, and signature.
  Certificate cert = parsePublicCertificate(publicCert);
  PublicKey pk = cert.getPublicKey();
  boolean isValid = verifySignature(blob, blobSignature, pk);

  return String.format(
      "isValid=%b for message: %s\n\tsignature: %s\n\tpublic cert: %s",
      isValid, message, Arrays.toString(blobSignature), Arrays.toString(publicCert));
}

기본 Cloud Storage 버킷 이름 가져오기

각 애플리케이션은 무료 저장용량 5GB 및 무료 I/O 작업 할당량을 포함하는 기본 Cloud Storage 버킷 하나를 보유할 수 있습니다.

App Identity API를 사용하여 기본 버킷 이름을 가져올 수 있습니다. AppIdentityService.getDefaultGcsBucketName을 호출하면 됩니다.