使用推送訂閱

Cloud Pub/Sub 支援推送和提取訊息傳送。如要瞭解提取和推送訂閱的概況,並對這兩者進行比較,請參閱訂閱者總覽。這份文件旨在說明推送傳遞機制,如果您想參考提取傳遞機制的相關討論,請閱讀提取訂閱者指南

您可以設定 Cloud Pub/Subsubscription,進而將所有訊息作為 HTTP POST 請求傳送至 Webhook、推送端點和網址。通常,推送端點必須是可公開存取的 HTTPS 伺服器,而這個伺服器需要提供由憑證授權單位簽署且可透過 DNS 路由的有效 SSL 憑證。您還必須驗證推送端點網域或網址路徑的擁有權,或是相同的存取層級。

另外,推送訂閱項目也可設定為提供驗證標頭,讓端點能夠授權請求。與訂閱項目一起託管在相同專案中的 App Engine 標準應用程式和 Cloud Functions 端點,都可以使用替代的驗證和授權機制 (可能採用較簡單驗證和授權方式)。

接收推送訊息

Cloud Pub/Sub 推送請求如下方範例所示。請注意,message.data 欄位是採用 base64 編碼格式

    POST https://www.example.com/my-push-endpoint 

   {
     "message": {
       "attributes": {
         "key": "value"
       },
       "data": "SGVsbG8gQ2xvdWQgUHViL1N1YiEgSGVyZSBpcyBteSBtZXNzYWdlIQ==",
       "messageId": "136969346945"
     },
     "subscription": "projects/myproject/subscriptions/mysubscription"
   }
您的推送端點需要處理收到的訊息並傳回 HTTP 狀態碼,才能表示操作成功或失敗。success 回應等同於系統確認了訊息。Cloud Pub/Sub 系統會將以下狀態碼解讀為訊息確認狀態,包括:200201202204102。成功的回應可能如下所示:

204 No Content

如果 Webhook 沒有傳回成功碼,則 Cloud Pub/Sub 在訂閱項目的訊息保留期限內會持續重新嘗試傳遞訊息,直到期限結束後訊息到期為止。您可以設定推送訂閱項目的預設確認期限,但與提取訂閱項目不同的是,個別訊息的期限無法延長。這個期限實際上是指端點回應推送請求所需的時間。

驗證及授權

使用 JSON Web Token (JWT)

您可以設定推送訂閱項目來建立服務帳戶身分與推送請求的關聯,使推送端點可以驗證這些請求。在推送訂閱項目上啟用驗證時,來自這個訂閱項目的推送請求會在授權標頭中加入 OpenIDConnect JWT。如此,推送端點即可使用這個符記來驗證系統是否代表與訂閱項目相關聯的服務帳戶發出請求,並藉此做出授權決策。

OpenIDConnect JWT 是由三個 base64 編碼格式的字串所組成,分別代表標頭、憑證附加資訊集和簽名,以英文句點 (.) 分隔。以下是授權標頭範例:

"Authorization" : "Bearer
eyJhbGciOiJSUzI1NiIsImtpZCI6IjdkNjgwZDhjNzBkNDRlOTQ3MTMzY2JkNDk5ZWJjMWE2MWMzZDVh
YmMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL2V4YW1wbGUuY29tIiwiYXpwIjoiMTEzNzc0M
jY0NDYzMDM4MzIxOTY0IiwiZW1haWwiOiJnYWUtZ2NwQGFwcHNwb3QuZ3NlcnZpY2VhY2NvdW50LmNvb
SIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJleHAiOjE1NTAxODU5MzUsImlhdCI6MTU1MDE4MjMzNSwia
XNzIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTEzNzc0MjY0NDYzMDM4MzIxO
TY0In0.QVjyqpmadTyDZmlX2u3jWd1kJ68YkdwsRZDo-QxSPbxjug4ucLBwAs2QePrcgZ6hhkvdc4UHY
4YF3fz9g7XHULNVIzX5xh02qXEH8dK6PgGndIWcZQzjSYfgO-q-R2oo2hNM5HBBsQN4ARtGK_acG-NGG
WM3CQfahbEjZPAJe_B8M7HfIu_G5jOLZCw2EUcGo8BvEwGcLWB2WqEgRM0-xt5-UPzoa3-FpSPG7DHk7
z9zRUeq6eB__ldb-2o4RciJmjVwHgnYqn3VvlX9oVKEgXpNFhKuYA-mWh5o7BCwhujSMmFoBOh6mbIXF
cyf5UiVqKjpqEbqPGo_AvKvIQ9VTQ" 

標頭和憑證附加資訊集都是 JSON 字串。經過解碼後,會呈現以下這樣的格式:

{"alg":"RS256","kid":"7d680d8c70d44e947133cbd499ebc1a61c3d5abc","typ":"JWT"}

{
   "aud":"https://example.com",
   "azp":"113774264463038321964",
   "email":"gae-gcp@appspot.gserviceaccount.com",
   "sub":"113774264463038321964",
   "email_verified":true,
   "exp":1550185935,
   "iat":1550182335,
   "iss":"https://accounts.google.com"
  }

這些符記的效期為一小時。

驗證 App Engine 標準應用程式和 Cloud Functions 網址

屬於 App Engine 標準應用程式或 Cloud Functions 的 Webhook 與訂閱項目位於相同專案內,其可使用較簡單的替代機制來保護推送網址。

處理 App Engine 應用程式時,您可以要求系統管理員登入,方能使用以下模式發出指向網址的推送請求:/_ah/push-handlers/.*

如要實現這個目的,您需要按照這個 Python 2 範例,在 app.yaml 中新增 login: admin 選項,或像在這個 Java 範例中一樣,新增 <security-constraint>。請注意,login: admin 不適用於 Python 3 應用程式。您需要在應用程式程式碼中實作應用程式邏輯,才能完成操作。詳情請參閱瞭解存取權控管一文。

Cloud Functions 適用的機制與上述內容類似,但該機制並不需要特定路徑。

設定 Cloud Pub/Sub 以進行推送驗證

訂閱項目的驗證設定包含兩個參數:

  • 服務帳戶:與推送訂閱項目相關聯的 GCP 服務帳戶。
  • 符記目標對象 (選用):一個不區分大小寫的字串,可供 Webhook 驗證這個特定符記的目標對象。

除了設定這些欄位外,您還必須授予 Cloud Pub/Sub 建立服務帳戶符記所需的權限。Cloud Pub/Sub 會為專案建立特別的服務帳戶 service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com.,並加以維護。這個服務帳戶需擁有「服務帳戶符記建立者」角色。如果您是使用 Cloud Console 設定要進行推送驗證的訂閱項目,則系統會自動授予這個角色。否則,您就必須將角色明確授予帳戶。

請注意,這項功能會逐漸推行至較舊的專案,因此在這項功能推出後,您的專案可能暫時不會有任何 Cloud Pub/Sub 服務帳戶,而所有新建立的專案皆可立即使用上述功能。如果您迫切需要在特定專案上啟用這項功能,請聯絡 cloud-pubsub@google.com

指令列

# grant Cloud Pub/Sub the permission to create tokens
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
 --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
 --role='roles/iam.serviceAccountTokenCreator'

# configure the subscription push identity
gcloud beta pubsub subscriptions (create|update|modify-push-config) ${SUBSCRIPTION} \
 --topic=${TOPIC} \
 --push-endpoint=${PUSH_ENDPOINT_URI} \
 --push-auth-service-account=${SERVICE_ACCOUNT_EMAIL} \
 --push-auth-token-audience=${OPTIONAL_AUDIENCE_OVERRIDE}

主控台

  1. 前往「Cloud Pub/Sub Topics」(Cloud Pub/Sub 主題) 頁面。

    前往「Topics」(主題) 頁面

  2. 按一下主題名稱。

  3. 建立或更新訂閱項目。

  4. 輸入身分,並視需要輸入目標對象。

透過推送端點進行驗證和授權

憑證附加資訊

JWT 可用來驗證憑證附加資訊 (包括 emailaud 憑證附加資訊) 是否由 Google 簽署。如要進一步瞭解如何使用 Google 的 OAuth 2.0 API 進行驗證和授權作業,請參閱 OpenID Connect 一文。

有兩種機制可讓這些憑證附加資訊更具實用價值。首先,Cloud Pub/Sub 會要求用來建立服務帳戶身分與推送訂閱項目關聯的使用者或服務帳戶,皆需擁有專案或服務帳戶的「服務帳戶使用者」角色。

其次,系統會嚴格控管用來簽署符記的憑證存取權。如要建立符記,Cloud Pub/Sub 必須使用不同的簽署服務帳戶身分來呼叫內部 Google 服務。簽署服務帳戶必須擁有所需權限,才能為宣告的服務帳戶或含有帳戶的專案建立符記。您可以使用 iam.serviceAccounts.getOpenIdToken 權限或「服務帳戶符記建立者」角色執行這項操作。

這個角色或權限可以授予任何帳戶,但您仍可使用 Cloud IAM 服務確保 Cloud Pub/Sub 簽署帳戶擁有這項權限。具體而言,Cloud Pub/Sub 會採用類似如下的服務帳戶:

service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com
  • {project_number}:包含訂閱項目的 GCP 專案。
  • gcp-sa-pubsub:包含簽署服務帳戶的 Google 專案。

驗證符記

以下範例說明如何驗證向 App Engine 應用程式提出的推送請求。

通訊協定

請求:

GET https://oauth2.googleapis.com/tokeninfo?id_token={BEARER_TOKEN}

回應:

200 OK
{
    "alg": "RS256",
    "aud": "example.com",
    "azp": "104176025330667568672",
    "email": "{SERVICE_ACCOUNT_NAME}@{YOUR_PROJECT_NAME}.iam.gserviceaccount.com",
    "email_verified": "true",
    "exp": "1555463097",
    "iat": "1555459497",
    "iss": "https://accounts.google.com",
    "kid": "3782d3f0bc89008d9d2c01730f765cfb19d3b70e",
    "sub": "104176025330667568672",
    "typ": "JWT"
}

Python

@app.route('/_ah/push-handlers/receive_messages', methods=['POST'])
def receive_messages_handler():
    # Verify that the request originates from the application.
    if (request.args.get('token', '') !=
            current_app.config['PUBSUB_VERIFICATION_TOKEN']):
        return 'Invalid request', 400

    # Verify that the push request originates from Cloud Pub/Sub.
    try:
        # Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
        bearer_token = request.headers.get('Authorization')
        token = bearer_token.split(' ')[1]
        TOKENS.append(token)

        # Verify and decode the JWT. `verify_oauth2_token` verifies
        # the JWT signature, the `aud` claim, and the `exp` claim.
        claim = id_token.verify_oauth2_token(token, requests.Request(),
                                             audience='example.com')
        # Must also verify the `iss` claim.
        if claim['iss'] not in [
            'accounts.google.com',
            'https://accounts.google.com'
        ]:
            raise ValueError('Wrong issuer.')
        CLAIMS.append(claim)
    except Exception as e:
        return 'Invalid token: {}\n'.format(e), 400

    envelope = json.loads(request.data.decode('utf-8'))
    payload = base64.b64decode(envelope['message']['data'])
    MESSAGES.append(payload)
    # Returning any 2xx status indicates successful receipt of the message.
    return 'OK', 200

您可以在網站專用的 Google 登入指南中找到有關驗證不記名 JWT 的其他範例。OpenID Connect 指南提供了更廣泛的 OpenID 符記總覽。

Cloud Run

Cloud Run 服務會自動驗證 HTTP 呼叫。使用者唯一要進行的設定,就是將必要的 IAM 角色授予呼叫端帳戶。舉例來說,您可以授予或撤銷呼叫帳戶特定 Cloud Run 端點的權限。

驗證網域擁有權

為防止產生不想要的流量,Cloud Pub/Sub 會要求您驗證推送端點的擁有權。所有端點都需要執行下列步驟,但以下項目除外:

  • Cloud Functions
  • Cloud Run
  • 與訂閱項目位於相同專案的 App Engine 標準應用程式

A. 確認您擁有網域的管理員權限:

請使用 Search Console 完成協作平台驗證程序。請務必註冊 https:// 版本的協作平台網址,詳情請參閱協作平台擁有權說明文件

B. 將存取權授予包含訂閱項目的專案:

如要讓 GCP 專案產生網域或端點網址的流量,您還必須將網域存取權授予含有訂閱項目的 GCP 專案:

  1. 前往「APIs & Services Credentials」(API 和服務憑證) 主控台頁面。
    前往「APIs & Services Credentials」(API 和服務憑證) 主控台頁面
  2. 必要時,請選取您要使用的專案。
  3. 選取「Domain verification」(網域驗證) 分頁標籤。
  4. 選取 [Add domain] (新增網域)
  5. 輸入網域並選取 [Add domain] (新增網域)

GCP 主控台會檢查您在「Search Console」中驗證的網域。假設您已正確驗證網域,頁面即會更新以顯示新的允許網域清單。

現在,您可以使用其中的任何網域來接收推送訊息。如要執行這項操作,則需在建立 Cloud Pub/Sub 訂閱項目時,將這些網域設定為端點。詳情請參閱設定訂閱項目一文。

停止傳遞與恢復傳遞

如要讓 Cloud Pub/Sub 暫時停止傳送請求至推送端點,請將訂閱項目變更為提取模式。請注意,此一變更可能需要幾分鐘的時間才會生效。

如要繼續傳遞推送訂閱項目,請再次將網址設定為有效端點。如要永久停止傳遞訂閱項目,則需刪除訂閱項目

配額、限制和傳送率

請注意,推送訂閱項目具有配額資源方面的限制。除此之外,系統會自動調整傳遞推送訂閱項目的速率,以便將傳送率最大化,同時也可減輕推送端點的負擔。系統會使用慢啟動演算法來完成這項操作。

  • 系統會先一次傳送一則訊息。
  • 每次傳遞成功後,並行傳送的訊息數量就會加倍。
  • 系統傳遞並行訊息的速率會持續加倍,一直到傳遞失敗,或是系統達到配額或資源限制為止。
  • 每次傳遞失敗後,向端點提出的並行請求數量就會減半,直到達到請求數下限為止 (每次提出一個請求)。

這個演算法會假設佇列中發布的訊息足以維持這個總處理量。最後,推送訂閱項目的傳送率會受到訊息發布的速率限制。

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

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

這個網頁
Cloud Pub/Sub 說明文件