Push-Abos

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Bei der Push-Zustellung initiiert Pub/Sub Anfragen an Ihre Abonnentenanwendung, um Nachrichten zuzustellen.

Hinweis

Bevor Sie dieses Dokument lesen, sollten Sie mit Folgendem vertraut sein:

Eigenschaften eines Push-Abos

Wenn Sie ein Push-Abo konfigurieren, können Sie die folgenden Attribute angeben.

  • Endpunkt-URL (erforderlich). Eine öffentlich zugängliche HTTPS-Adresse. Der Server für den Push-Endpunkt muss ein gültiges SSL-Zertifikat haben, das von einer Zertifizierungsstelle signiert wurde. Der Pub/Sub-Dienst sendet Nachrichten an Push-Endpunkte aus derselben Google Cloud-Region, in der der Pub/Sub-Dienst die Nachrichten speichert. Der Pub/Sub-Dienst sendet Nachrichten aus derselben Google Cloud-Region auf Best-Effort-Basis.

    Pub/Sub erfordert für Domain-Push-Abos nicht mehr einen Nachweis der Inhaberschaft. Wenn Ihre Domain unerwartete POST-Anfragen von Pub/Sub empfängt, können Sie verdächtigen Missbrauch melden.

  • Authentifizierung aktivieren Wenn diese Option aktiviert ist, enthalten Nachrichten, die von Pub/Sub an den Push-Endpunkt gesendet werden, einen Autorisierungsheader, mit dem der Endpunkt die Anfrage authentifizieren kann. Die automatischen Authentifizierungs- und Autorisierungsmechanismen sind für App Engine-Standard- und Cloud Functions-Endpunkte verfügbar, die im selben Projekt wie das Abo gehostet werden.

Die Authentifizierungskonfiguration für ein authentifiziertes Push-Abo besteht aus einem vom Nutzer verwalteten Dienstkonto und den Zielgruppenparametern, die in einem create-, patch- oder ModifyPushConfig-Aufruf angegeben werden. Sie müssen auch einem speziellen von Google verwalteten Dienstkonto eine bestimmte Rolle zuweisen. Dies wird im nächsten Abschnitt beschrieben.

  • Vom Nutzer verwaltetes Dienstkonto (erforderlich) Das mit dem Push-Abo verknüpfte Dienstkonto. Dieses Konto wird als email-Anforderung des generierten JSON-Webtokens (JWT) verwendet. Im Folgenden finden Sie eine Liste der Anforderungen für das Dienstkonto:

  • Zielgruppe: Ein einzelner String ohne Berücksichtigung der Groß- und Kleinschreibung, mit dem der Webhook die beabsichtigte Zielgruppe dieses bestimmten Tokens validiert.

  • Von Google verwaltetes Dienstkonto (erforderlich).

    • Pub/Sub erstellt automatisch ein Dienstkonto im Format service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com.

    • Diesem Dienstkonto muss die in der Rolle roles/iam.serviceAccountTokenCreator enthaltene Berechtigung iam.serviceAccounts.getOpenIdToken gewährt werden, damit Pub/Sub JWT-Tokens für authentifizierte Push-Anfragen erstellen kann.

Push-Abo und VPC Service Controls

Beachten Sie für ein Projekt, das durch VPC Service Controls geschützt ist, die folgenden Einschränkungen für Push-Abos:

  • Sie können nur neue Push-Abos erstellen, für die der Push-Endpunkt auf einen Cloud Run-Dienst mit der Standard-URL run.app gesetzt ist. Benutzerdefinierte Domains funktionieren nicht.

  • Wenn Sie Ereignisse über Eventarc zu Workflows-Zielen weiterleiten, für die der Push-Endpunkt auf eine Workflow-Ausführung festgelegt ist, können Sie neue Push-Abos nur über Eventarc erstellen.

  • Sie können vorhandene Push-Abos nicht aktualisieren. Diese Push-Abos funktionieren weiterhin, obwohl sie nicht durch VPC Service Controls geschützt sind.

Nachrichten empfangen

Wenn Pub/Sub eine Nachricht an einen Push-Endpunkt sendet, sendet Pub/Sub die Nachricht im Text einer POST-Anfrage. Der Anfragetext ist ein JSON-Objekt und die Nachrichtendaten befinden sich im Feld message.data. Die Nachrichtendaten sind Base64-codiert.

Das folgende Beispiel zeigt den Text einer POST-Anfrage an einen Push-Endpunkt:

{
    "message": {
        "attributes": {
            "key": "value"
        },
        "data": "SGVsbG8gQ2xvdWQgUHViL1N1YiEgSGVyZSBpcyBteSBtZXNzYWdlIQ==",
        "messageId": "2070443601311540",
        "message_id": "2070443601311540",
        "publishTime": "2021-02-26T19:13:55.749Z",
        "publish_time": "2021-02-26T19:13:55.749Z"
    },
   "subscription": "projects/myproject/subscriptions/mysubscription"
}

Wenn Sie Nachrichten von Push-Abos erhalten möchten, verwenden Sie einen Webhook und verarbeiten Sie die POST-Anfragen, die Pub/Sub an den Push-Endpunkt sendet. Weitere Informationen zum Verarbeiten dieser POST-Anfragen in App Engine finden Sie unter Pub/Sub-Nachrichten schreiben und beantworten.

Wenn Sie eine Push-Anfrage erhalten haben, geben Sie einen HTTP-Statuscode zurück. Um die Nachricht zu bestätigen, geben Sie einen der folgenden Statuscodes zurück:

  • 102
  • 200
  • 201
  • 202
  • 204

Wenn Sie eine negative Bestätigung für die Nachricht senden möchten, müssen Sie einen anderen Statuscode zurückgeben. Wenn Sie eine negative Bestätigung senden oder die Fristfrist abläuft, sendet Pub/Sub die Nachricht noch einmal. Sie können die Bestätigungsfrist einzelner Nachrichten, die Sie über Push-Abos erhalten, nicht ändern.

Authentifizierung für Push-Abo

Wenn für ein Push-Abo die Authentifizierung verwendet wird, signiert der Pub/Sub-Dienst ein JWT und sendet das JWT im Autorisierungsheader der Push-Anfrage. Das JWT enthält Ansprüche und eine Signatur.

Abonnenten können das JWT validieren und Folgendes prüfen:

  • Die Ansprüche sind korrekt.
  • Der Pub/Sub-Dienst hat die Ansprüche signiert.

Wenn Abonnenten eine Firewall verwenden, können sie keine Push-Anfragen empfangen. Um Push-Anfragen zu erhalten, müssen Sie die Firewall deaktivieren und das JWT prüfen.

JWT-Format

Das JWT ist ein OpenIDConnect-JWT, das aus einem Header, einem Anforderungssatz und einer Signatur besteht. Der Pub/Sub-Dienst codiert das JWT als base64-String mit Punkttrennzeichen.

Der folgende Autorisierungsheader enthält beispielsweise ein codiertes JWT:

"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" 

Der Header und der Anforderungssatz sind JSON-Strings. Nach der Decodierung nehmen sie die folgende Form an:

{"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"
  }

Die an Anfragen angehängten Tokens an Push-Endpunkte können bis zu einer Stunde alt sein.

Pub/Sub für Push-Authentifizierung konfigurieren

Das folgende Beispiel zeigt, wie Sie das Push Auth-Dienstkonto auf ein Dienstkonto Ihrer Wahl festlegen und die Rolle Von Google verwaltetes Dienstkonto service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com der Rolle iam.serviceAccountTokenCreator zuweisen.

Console

  1. Rufen Sie die Seite Pub/Sub-Abos auf.

    Zur Seite "Abos"

  2. Klicken Sie auf Abo erstellen.

  3. Geben Sie in das Feld Abo-ID einen Namen ein.

  4. Wählen Sie ein Thema aus.

  5. Wählen Sie Push als Zustellungstyp aus.

  6. Geben Sie eine Endpunkt-URL ein.

  7. Setzen Sie ein Häkchen bei Authentifizierung aktivieren.

  8. Wählen Sie ein Dienstkonto aus.

  9. Achten Sie darauf, dass das von Google verwaltete Dienstkonto service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com die Rolle iam.serviceAccountTokenCreator im IAM-Dashboard Ihres Projekts hat. Wenn dem Dienstkonto die Rolle nicht gewährt wurde, klicken Sie im IAM-Dashboard auf Gewähren.

  10. Optional: Geben Sie eine Zielgruppe ein.

  11. Klicken Sie auf Erstellen.

gcloud

# Configure the push subscription
gcloud 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}

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
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'

Wenn Sie ein authentifiziertes Push-Abo mit einer App Engine-Anwendung verwenden, die mit einem Identity-Aware Proxy gesichert ist, müssen Sie die IAP-Client-ID als Zielgruppe für das Push-Authentifizierungstoken angeben. Informationen zum Aktivieren von IAP in Ihrer App Engine-Anwendung finden Sie unter IAP aktivieren. Die IAP-Client-ID finden Sie auf der Seite Anmeldedaten unter IAP-App-Engine-app-Client-ID.

Ansprüche

Mit dem JWT kann sichergestellt werden, dass die Anforderungen (einschließlich der email- und aud-Anforderungen) von Google unterzeichnet werden. Weitere Informationen dazu, wie die OAuth 2.0 APIs von Google sowohl für die Authentifizierung als auch für die Autorisierung verwendet werden können, finden Sie unter OpenID Connect.

Es gibt zwei Mechanismen, mit denen Sie diese Anforderungen nutzbar machen. Pub/Sub erfordert, dass der Nutzer oder das Dienstkonto, der den Aufruf „CreateSubscription“, „UpdateSubscription“ oder „ModifyPushConfig“ ausführt, eine Rolle mit der Berechtigung iam.serviceAccounts.actAs für das Push-Authentifizierungsdienstkonto haben muss. Ein Beispiel für eine solche Rolle ist die Rolle roles/iam.serviceAccountUser.

Zweitens wird der Zugriff auf die zum Signieren der Tokens verwendeten Zertifikate streng kontrolliert. Pub/Sub muss einen internen Google-Dienst mit einer separaten Dienstkontoidentität für das Signieren aufrufen, um das Token zu erstellen. Dies ist das von Google verwaltete Dienstkonto service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com. Dieses Signaturdienstkonto muss die Berechtigung iam.serviceAccounts.getOpenIdToken oder die Rolle Ersteller von Dienstkonto-Tokens (roles/iam.serviceAccountTokenCreator) für das Push-Authentifizierungsdienstkonto oder für eine beliebige Ancestor-Ressource, z. B. das Projekt des Push-Authentifizierungsdienstkontos, haben.

Tokens validieren

Die Validierung von Tokens, die von Pub/Sub an den Push-Endpunkt gesendet werden, umfasst folgende Aufgaben:

  • Die Tokenintegrität mithilfe der Signaturvalidierung prüfen.
  • Achten Sie darauf, dass die Anforderungen E-Mail und Zielgruppe im Token mit den Werten übereinstimmen, die in der Konfiguration des Push-Abo festgelegt wurden.

Das folgende Beispiel zeigt, wie eine Push-Anfrage an eine App Engine-Anwendung authentifiziert wird, die nicht mit Identity-Aware Proxy gesichert ist. Wenn Ihre App Engine-Anwendung mit IAP gesichert ist, ist der HTTP-Anforderungsheader, der das IAP-JWT enthält, x-goog-iap-jwt-assertion und muss entwertetgeprüft werden.

Protokoll

Anfrage:

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

Antwort:

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"
}

C#

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für C# in der Schnellstart-Anleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub C# API.

        /// <summary>
        /// Extended JWT payload to match the pubsub payload format.
        /// </summary>
        public class PubSubPayload : JsonWebSignature.Payload
        {
            [JsonProperty("email")]
            public string Email { get; set; }
            [JsonProperty("email_verified")]
            public string EmailVerified { get; set; }
        }
        /// <summary>
        /// Handle authenticated push request coming from pubsub.
        /// </summary>
        [HttpPost]
        [Route("/AuthPush")]
        public async Task<IActionResult> AuthPushAsync([FromBody] PushBody body, [FromQuery] string token)
        {
            // Get the Cloud Pub/Sub-generated "Authorization" header.
            string authorizaionHeader = HttpContext.Request.Headers["Authorization"];
            string verificationToken = token ?? body.message.attributes["token"];
            // JWT token comes in `Bearer <JWT>` format substring 7 specifies the position of first JWT char.
            string authToken = authorizaionHeader.StartsWith("Bearer ") ? authorizaionHeader.Substring(7) : null;
            if (verificationToken != _options.VerificationToken || authToken is null)
            {
                return new BadRequestResult();
            }
            // Verify and decode the JWT.
            // Note: For high volume push requests, it would save some network
            // overhead if you verify the tokens offline by decoding them using
            // Google's Public Cert; caching already seen tokens works best when
            // a large volume of messages have prompted a single push server to
            // handle them, in which case they would all share the same token for
            // a limited time window.
            var payload = await JsonWebSignature.VerifySignedTokenAsync<PubSubPayload>(authToken);

            // IMPORTANT: you should validate payload details not covered
            // by signature and audience verification above, including:
            //   - Ensure that `payload.Email` is equal to the expected service
            //     account set up in the push subscription settings.
            //   - Ensure that `payload.Email_verified` is set to true.

            var messageBytes = Convert.FromBase64String(body.message.data);
            string message = System.Text.Encoding.UTF8.GetString(messageBytes);
            s_authenticatedMessages.Add(message);
            return new OkResult();
        }

Einfach loslegen (Go)

// receiveMessagesHandler validates authentication token and caches the Pub/Sub
// message received.
func (a *app) receiveMessagesHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
		return
	}

	// Verify that the request originates from the application.
	// a.pubsubVerificationToken = os.Getenv("PUBSUB_VERIFICATION_TOKEN")
	if token, ok := r.URL.Query()["token"]; !ok || len(token) != 1 || token[0] != a.pubsubVerificationToken {
		http.Error(w, "Bad token", http.StatusBadRequest)
		return
	}

	// Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" || len(strings.Split(authHeader, " ")) != 2 {
		http.Error(w, "Missing Authorization header", http.StatusBadRequest)
		return
	}
	token := strings.Split(authHeader, " ")[1]
	// Verify and decode the JWT.
	// If you don't need to control the HTTP client used you can use the
	// convenience method idtoken.Validate instead of creating a Validator.
	v, err := idtoken.NewValidator(r.Context(), option.WithHTTPClient(a.defaultHTTPClient))
	if err != nil {
		http.Error(w, "Unable to create Validator", http.StatusBadRequest)
		return
	}
	// Please change http://example.com to match with the value you are
	// providing while creating the subscription.
	payload, err := v.Validate(r.Context(), token, "http://example.com")
	if err != nil {
		http.Error(w, fmt.Sprintf("Invalid Token: %v", err), http.StatusBadRequest)
		return
	}
	if payload.Issuer != "accounts.google.com" && payload.Issuer != "https://accounts.google.com" {
		http.Error(w, "Wrong Issuer", http.StatusBadRequest)
		return
	}

	// IMPORTANT: you should validate claim details not covered by signature
	// and audience verification above, including:
	//   - Ensure that `payload.Claims["email"]` is equal to the expected service
	//     account set up in the push subscription settings.
	//   - Ensure that `payload.Claims["email_verified"]` is set to true.
	if payload.Claims["email"] != "test-service-account-email@example.com" || payload.Claims["email_verified"] != true {
		http.Error(w, "Unexpected email identity", http.StatusBadRequest)
		return
	}

	var pr pushRequest
	if err := json.NewDecoder(r.Body).Decode(&pr); err != nil {
		http.Error(w, fmt.Sprintf("Could not decode body: %v", err), http.StatusBadRequest)
		return
	}

	a.messagesMu.Lock()
	defer a.messagesMu.Unlock()
	// Limit to ten.
	a.messages = append(a.messages, pr.Message.Data)
	if len(a.messages) > maxMessages {
		a.messages = a.messages[len(a.messages)-maxMessages:]
	}

	fmt.Fprint(w, "OK")
}

Java

@WebServlet(value = "/pubsub/authenticated-push")
public class PubSubAuthenticatedPush extends HttpServlet {
  private final String pubsubVerificationToken = System.getenv("PUBSUB_VERIFICATION_TOKEN");
  private final MessageRepository messageRepository;
  private final GoogleIdTokenVerifier verifier =
      new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new JacksonFactory())
          /**
           * Please change example.com to match with value you are providing while creating
           * subscription as provided in @see <a
           * href="https://github.com/GoogleCloudPlatform/java-docs-samples/tree/main/appengine-java8/pubsub">README</a>.
           */
          .setAudience(Collections.singletonList("example.com"))
          .build();
  private final Gson gson = new Gson();
  private final JsonParser jsonParser = new JsonParser();

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws IOException, ServletException {

    // Verify that the request originates from the application.
    if (req.getParameter("token").compareTo(pubsubVerificationToken) != 0) {
      resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
      return;
    }
    // Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
    String authorizationHeader = req.getHeader("Authorization");
    if (authorizationHeader == null
        || authorizationHeader.isEmpty()
        || authorizationHeader.split(" ").length != 2) {
      resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
      return;
    }
    String authorization = authorizationHeader.split(" ")[1];

    try {
      // Verify and decode the JWT.
      // Note: For high volume push requests, it would save some network overhead
      // if you verify the tokens offline by decoding them using Google's Public
      // Cert; caching already seen tokens works best when a large volume of
      // messsages have prompted a single push server to handle them, in which
      // case they would all share the same token for a limited time window.
      GoogleIdToken idToken = verifier.verify(authorization);

      GoogleIdToken.Payload payload = idToken.getPayload();
      // IMPORTANT: you should validate claim details not covered by signature
      // and audience verification above, including:
      //   - Ensure that `payload.getEmail()` is equal to the expected service
      //     account set up in the push subscription settings.
      //   - Ensure that `payload.getEmailVerified()` is set to true.

      messageRepository.saveToken(authorization);
      messageRepository.saveClaim(payload.toPrettyString());
      // parse message object from "message" field in the request body json
      // decode message data from base64
      Message message = getMessage(req);
      messageRepository.save(message);
      // 200, 201, 204, 102 status codes are interpreted as success by the Pub/Sub system
      resp.setStatus(102);
      super.doPost(req, resp);
    } catch (Exception e) {
      resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
    }
  }

  private Message getMessage(HttpServletRequest request) throws IOException {
    String requestBody = request.getReader().lines().collect(Collectors.joining("\n"));
    JsonElement jsonRoot = jsonParser.parse(requestBody);
    String messageStr = jsonRoot.getAsJsonObject().get("message").toString();
    Message message = gson.fromJson(messageStr, Message.class);
    // decode from base64
    String decoded = decode(message.getData());
    message.setData(decoded);
    return message;
  }

  private String decode(String data) {
    return new String(Base64.getDecoder().decode(data));
  }

  PubSubAuthenticatedPush(MessageRepository messageRepository) {
    this.messageRepository = messageRepository;
  }

  public PubSubAuthenticatedPush() {
    this(MessageRepositoryImpl.getInstance());
  }
}

Node.js

app.post('/pubsub/authenticated-push', jsonBodyParser, async (req, res) => {
  // Verify that the request originates from the application.
  if (req.query.token !== PUBSUB_VERIFICATION_TOKEN) {
    res.status(400).send('Invalid request');
    return;
  }

  // Verify that the push request originates from Cloud Pub/Sub.
  try {
    // Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
    const bearer = req.header('Authorization');
    const [, token] = bearer.match(/Bearer (.*)/);
    tokens.push(token);

    // Verify and decode the JWT.
    // Note: For high volume push requests, it would save some network
    // overhead if you verify the tokens offline by decoding them using
    // Google's Public Cert; caching already seen tokens works best when
    // a large volume of messages have prompted a single push server to
    // handle them, in which case they would all share the same token for
    // a limited time window.
    const ticket = await authClient.verifyIdToken({
      idToken: token,
      audience: 'example.com',
    });

    const claim = ticket.getPayload();

    // IMPORTANT: you should validate claim details not covered
    // by signature and audience verification above, including:
    //   - Ensure that `claim.email` is equal to the expected service
    //     account set up in the push subscription settings.
    //   - Ensure that `claim.email_verified` is set to true.

    claims.push(claim);
  } catch (e) {
    res.status(400).send('Invalid token');
    return;
  }

  // The message is a unicode string encoded in base64.
  const message = Buffer.from(req.body.message.data, 'base64').toString(
    'utf-8'
  );

  messages.push(message);

  res.status(200).send();
});

Python

@app.route('/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.
        # Note: For high volume push requests, it would save some network
        # overhead if you verify the tokens offline by downloading Google's
        # Public Cert and decode them using the `google.auth.jwt` module;
        # caching already seen tokens works best when a large volume of
        # messages have prompted a single push server to handle them, in which
        # case they would all share the same token for a limited time window.
        claim = id_token.verify_oauth2_token(token, requests.Request(),
                                             audience='example.com')

        # IMPORTANT: you should validate claim details not covered by signature
        # and audience verification above, including:
        #   - Ensure that `claim["email"]` is equal to the expected service
        #     account set up in the push subscription settings.
        #   - Ensure that `claim["email_verified"]` is set to true.

        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

Ruby

post "/pubsub/authenticated-push" do
  halt 400 if params[:token] != PUBSUB_VERIFICATION_TOKEN

  begin
    bearer = request.env["HTTP_AUTHORIZATION"]
    token = /Bearer (.*)/.match(bearer)[1]
    claim = Google::Auth::IDTokens.verify_oidc token, aud: "example.com"

    # IMPORTANT: you should validate claim details not covered by signature
    # and audience verification above, including:
    #   - Ensure that `claim["email"]` is equal to the expected service
    #     account set up in the push subscription settings.
    #   - Ensure that `claim["email_verified"]` is set to true.

    claims.push claim
  rescue Google::Auth::IDTokens::VerificationError => e
    puts "VerificationError: #{e.message}"
    halt 400, "Invalid token"
  end

  message = JSON.parse request.body.read
  payload = Base64.decode64 message["message"]["data"]

  messages.push payload
end

Informationen zur Umgebungsvariable PUBSUB_VERIFICATION_TOKEN, die in den Codebeispielen oben verwendet wird, finden Sie unter Pub/Sub-Nachrichten schreiben und beantworten.

Weitere Beispiele zur Validierung des Inhaber-JWT finden Sie in diesem Leitfaden für Google Log-in für Websites. Eine umfassendere Übersicht über OpenID-Tokens finden Sie im Handbuch zu OpenID Connect. Dort finden Sie auch eine Liste von Clientbibliotheken, mit denen JWTs validiert werden können.

Authentifizierung über andere Google Cloud-Dienste

Cloud Run, App Engine und Cloud Functions authentifizieren HTTP-Aufrufe von Pub/Sub. Dazu prüfen Sie die von Pub/Sub generierten Tokens. Die einzige erforderliche Konfiguration besteht darin, dem Aufrufer-Konto die erforderlichen IAM-Rollen zuzuweisen.

In den folgenden Leitfäden und Anleitungen finden Sie verschiedene Anwendungsfälle für diese Dienste:

Cloud Run:

Google App Engine:

Cloud Functions:

  • HTTP-Trigger: Ihr Push-Auth-Dienstkonto muss die Rolle roles/cloudfunctions.invoker haben, um eine Funktion aufzurufen, wenn Sie Pub/Sub-Push-Anfragen als HTTP-Trigger für die Funktion verwenden möchten.
  • Google Cloud Pub/Sub-Trigger: IAM-Rollen und -Berechtigungen werden automatisch konfiguriert, wenn Sie mit Pub/Sub-Triggern eine Funktion aufrufen

Nachrichtenzustellungen verwalten

Zustellung von Nachrichten beenden und fortsetzen

Sie können das Senden von Anfragen an den Push-Endpunkt in Pub/Sub vorübergehend anhalten. Ändern Sie dazu das Abo in Pull. Es kann einige Minuten dauern, bis die Änderung wirksam wird.

Zum Fortsetzen der Push-Zustellung wählen Sie für die URL wieder einen gültigen Endpunkt aus. Löschen Sie das Abo, wenn Sie die Zustellung dauerhaft stoppen möchten.

Push-Backoff

Wenn ein Push-Abonnent zu viele negative Bestätigungen sendet, beginnt Pub/Sub möglicherweise, Nachrichten mit einem Push-Backoff zuzustellen. Wenn Pub/Sub einen Push-Backoff verwendet, werden keine Nachrichten mehr für einen vorab festgelegten Zeitraum gesendet. Diese Zeitspanne kann zwischen 100 Millisekunden und 60 Sekunden liegen. Nach Ablauf der Zeit sendet Pub/Sub wieder Nachrichten.

Funktionsweise des Push-Backoffs

Push-Backoff verwendet einen exponentiellen Backoff-Algorithmus, um die Verzögerung zu bestimmen, die Pub/Sub zwischen dem Senden von Nachrichten verwendet. Diese Zeit wird anhand der Anzahl negativer Bestätigungen berechnet, die Abonnenten senden.

Wenn ein Push-Abonnent beispielsweise fünf Nachrichten pro Sekunde empfängt und eine negative Bestätigung pro Sekunde sendet, stellt Pub/Sub Nachrichten etwa alle 500 Millisekunden zu. Wenn der Push-Abonnent fünf negative Bestätigungen pro Sekunde sendet, sendet Pub/Sub Nachrichten alle 30 bis 60 Sekunden.

Beachten Sie die folgenden Überlegungen zu Pushback:

  • Push-Backoff kann nicht aktiviert oder deaktiviert werden. Sie können auch nicht die Werte ändern, die zur Berechnung der Verzögerung verwendet werden.
  • Pushoff-Trigger für die folgenden Aktionen:
    • Wenn eine negative Bestätigung empfangen wird.
    • Wann die Bestätigungsfrist einer Nachricht abläuft.
  • Push-Backoffs gelten für alle Nachrichten in einem Abo (global).

Zustellungsrate

Pub/Sub passt die Anzahl der gleichzeitigen Push-Anfragen mit einem Slow-Start-Algorithmus an. Die maximal zulässige Anzahl gleichzeitiger Push-Anfragen ist das Push-Fenster. Das Push-Fenster wird bei erfolgreicher Zustellung vergrößert und bei einem Fehler verringert. Das System beginnt mit einer kleinen einstelligen Fenstergröße.

Wenn ein Abonnent Nachrichten bestätigt, vergrößert sich das Fenster exponentiell. Bei Abos, bei denen Abonnenten mehr als 99% der Nachrichten und eine durchschnittliche Latenz von weniger als einer Sekunde der Push-Anfragelatenz bestätigen, sollte das Push-Fenster so weit erweitert werden, dass es mit dem Veröffentlichungsdurchsatz Schritt halten kann.

Die Latenz der Push-Anfrage umfasst Folgendes:

Nach 3.000 ausstehenden Nachrichten pro Region wird das Fenster linear vergrößert,um zu verhindern, dass der Push-Endpunkt zu viele Nachrichten empfängt. Wenn die durchschnittliche Latenz eine Sekunde überschreitet oder der Abonnent weniger als 99% der Anfragen bestätigt, verringert sich das Fenster auf das untere Limit von 3.000 ausstehenden Nachrichten.

Weitere Informationen zu den Messwerten, die Sie für das Monitoring der Push-Zustellung verwenden können, finden Sie unter Push-Abos beobachten.

Kontingente und Limits

Push-Abos unterliegen einer Reihe von Kontingenten und Ressourcenlimits.