App Identity Python API 總覽

App Identity API 可讓應用程式找到自己的應用程式 ID (也稱為專案 ID)。使用這個 ID,App Engine 應用程式就可以向其他 App Engine 應用程式、Google API 及第三方應用程式與服務宣告自己的身分。此應用程式 ID 也可用來產生網址或電子郵件地址,或是建立執行階段決策。

取得專案 ID

您可以使用 app_identity.get_application_id() 方法找出應用程式 ID。WSGI 或 CGI 環境會公開一些由 API 處理的實作詳情。

取得應用程式主機名稱

根據預設,App Engine 應用程式是由 http://<your_app_id>.appspot.com 格式的網址提供服務,其中應用程式 ID 是主機名稱的一部分。如果應用程式是由自訂網域提供服務,則可能需要擷取完整的主機名稱元件。您可以使用 app_identity.get_default_version_hostname() 方法來執行這項作業。

向其他 App Engine 應用程式宣告身分

針對向您的 App Engine 應用程式發出要求的 App Engine 應用程式,您可以使用要求標頭 X-Appengine-Inbound-Appid 來辨識其身分。這個標頭是由 URLFetch 服務加入要求,使用者無法修改,因此發出要求的應用程式 ID 如果存在,便能確切指出。

必要條件:

  • 只有向您應用程式 appspot.com 網域發出的呼叫會含有 X-Appengine-Inbound-Appid 標頭。對自訂網域的呼叫不含標頭。
  • 必須將要求設定為不追蹤重新導向。將 urlfetch.fetch() follow_redirects 參數設為 False

在應用程式處理常式中,您可以讀取 X-Appengine-Inbound-Appid 標頭並比對允許發出要求的 ID 清單,藉此檢查傳入的 ID。例如:

import webapp2

class MainPage(webapp2.RequestHandler):
    allowed_app_ids = [
        'other-app-id',
        'other-app-id-2'
    ]

    def get(self):
        incoming_app_id = self.request.headers.get(
            'X-Appengine-Inbound-Appid', None)

        if incoming_app_id not in self.allowed_app_ids:
            self.abort(403)

        self.response.write('This is a protected page.')

app = webapp2.WSGIApplication([
    ('/', MainPage)
], debug=True)

向 Google API 宣告身分

Google API 使用 OAuth 2.0 通訊協定進行驗證及授權。App Identity API 可建立 OAuth 憑證,用來宣告要求來源是應用程式本身。get_access_token() 方法會傳回單一範圍或列有多範圍清單的存取憑證。接著可在呼叫的 HTTP 標頭中設定這個憑證,以識別呼叫應用程式。

以下範例顯示如何使用 App Identity API 來驗證 Cloud Storage API,並且擷取專案中所有值區的清單。
import json
import logging

from google.appengine.api import app_identity
from google.appengine.api import urlfetch
import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        auth_token, _ = app_identity.get_access_token(
            'https://www.googleapis.com/auth/cloud-platform')
        logging.info(
            'Using token {} to represent identity {}'.format(
                auth_token, app_identity.get_service_account_name()))

        response = urlfetch.fetch(
            'https://www.googleapis.com/storage/v1/b?project={}'.format(
                app_identity.get_application_id()),
            method=urlfetch.GET,
            headers={
                'Authorization': 'Bearer {}'.format(auth_token)
            }
        )

        if response.status_code != 200:
            raise Exception(
                'Call failed. Status code {}. Body {}'.format(
                    response.status_code, response.content))

        result = json.loads(response.content)
        self.response.headers['Content-Type'] = 'application/json'
        self.response.write(json.dumps(result, indent=2))

app = webapp2.WSGIApplication([
    ('/', MainPage)
], debug=True)

請注意,應用程式的身分是以服務帳戶名稱表示,通常為「applicationid@appspot.gserviceaccount.com」。您可以使用 get_service_account_name() 方法取得確切的值。對於提供 ACL 的服務,您可以透過授予這個帳戶存取權的方式,以授予應用程式存取權。

向第三方服務宣告身分

get_access_token() 產生的憑證只適用於 Google 服務。但您可以使用基本的簽署技術,向其他服務宣告應用程式的身分。sign_blob() 方法會利用應用程式專用的私密金鑰簽署位元組,而 get_public_certificates() 方法會傳回可用來驗證簽名的憑證。

以下範例顯示如何簽署 blob 並驗證其簽名:

import base64

from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Util.asn1 import DerSequence
from google.appengine.api import app_identity
import webapp2

def verify_signature(data, signature, x509_certificate):
    """Verifies a signature using the given x.509 public key certificate."""

    # PyCrypto 2.6 doesn't support x.509 certificates directly, so we'll need
    # to extract the public key from it manually.
    # This code is based on https://github.com/google/oauth2client/blob/master
    # /oauth2client/_pycrypto_crypt.py
    pem_lines = x509_certificate.replace(b' ', b'').split()
    cert_der = base64.urlsafe_b64decode(b''.join(pem_lines[1:-1]))
    cert_seq = DerSequence()
    cert_seq.decode(cert_der)
    tbs_seq = DerSequence()
    tbs_seq.decode(cert_seq[0])
    public_key = RSA.importKey(tbs_seq[6])

    signer = PKCS1_v1_5.new(public_key)
    digest = SHA256.new(data)

    return signer.verify(digest, signature)

def verify_signed_by_app(data, signature):
    """Checks the signature and data against all currently valid certificates
    for the application."""
    public_certificates = app_identity.get_public_certificates()

    for cert in public_certificates:
        if verify_signature(data, signature, cert.x509_certificate_pem):
            return True

    return False

class MainPage(webapp2.RequestHandler):
    def get(self):
        message = 'Hello, world!'
        signing_key_name, signature = app_identity.sign_blob(message)
        verified = verify_signed_by_app(message, signature)

        self.response.content_type = 'text/plain'
        self.response.write('Message: {}\n'.format(message))
        self.response.write(
            'Signature: {}\n'.format(base64.b64encode(signature)))
        self.response.write('Verified: {}\n'.format(verified))

app = webapp2.WSGIApplication([
    ('/', MainPage)
], debug=True)

取得預設的 Cloud Storage 值區名稱

每個應用程式都有一個預設的 Cloud Storage 值區,其中包含 5GB 的免費儲存空間及免費的 I/O 作業配額。這個值區的儲存空間上限為 5 GB;如要增加儲存空間,可以為您的應用程式啟用記費功能,並支付額外儲存空間的費用,讓這個值區成為付費值區。

如要取得預設值區的名稱,您可以使用 App Identity API。請呼叫 google.appengine.api.app_identity.app_identity.get_default_gcs_bucket_name

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Python 2 適用的 App Engine 標準環境