Push-Abos

Bei der Push-Zustellung initiiert Pub/Sub Anfragen an deine Abonnentenanwendung, um Nachrichten zu übermitteln.

Hinweis

Bevor Sie dieses Dokument lesen, machen Sie sich mit folgenden Themen vertraut:

Eigenschaften eines Push-Abos

Beim Konfigurieren eines Push-Abos können Sie die folgenden Properties 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 Inhaber von Push-Abo-URLs keine Nachweise der Inhaberschaft mehr. Falls Ihre Domain unerwartete POST-Anfragen von Pub/Sub erhält, 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 dem Dienstkonto und den Zielgruppenparametern, die in einem create-, patch- oder ModifyPushConfig-Aufruf angegeben sind:

Push-Abo und VPC Service Controls

Sie können keine neuen Push-Abos für Projekte erstellen, die durch VPC Service Controls geschützt sind, es sei denn, die Push-Endpunkte sind auf Cloud Run-Dienste mit standardmäßigen run.app-URLs festgelegt. Benutzerdefinierte Domains funktionieren nicht.

Vorhandene Push-Abos können nicht für Projekte aktualisiert werden, die durch VPC Service Controls geschützt sind. Vorhandene Push-Abos funktionieren weiterhin, obwohl sie nicht durch VPC Service Controls geschützt sind. Weitere Informationen erhalten Sie auf Google Cloud.

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, geben Sie einen beliebigen anderen Statuscode zurück. Wenn Sie eine negative Bestätigung oder die Bestätigungsfrist senden, wird die Nachricht von Pub/Sub noch einmal gesendet. Du kannst die Bestätigungsfrist für einzelne Nachrichten, die du von Push-Abos erhältst, nicht ändern.

Authentifizierung für Push-Abo

Wenn für ein Push-Abo eine 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-Authentifizierungsdienstkonto auf ein Dienstkonto Ihrer Wahl festlegen und die Rolle Von Google verwaltetes Dienstkonto service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com 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 Auslieferungstyp aus.

  6. Geben Sie eine Endpunkt-URL ein.

  7. Klicken Sie das Kästchen Authentifizierung aktivieren an.

  8. Wählen Sie ein Dienstkonto aus.

  9. Optional: Klicken Sie auf Gewähren, um dem von Google verwalteten Dienstkonto service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com die Rolle iam.serviceAccountTokenCreator zu gewähren, falls sie die Rolle nicht bereits hat.

  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}

# Only needed for projects created on or before April 8, 2021:
# Grant the Google-managed service account 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 Identity-Aware Proxy gesichert ist, müssen Sie die IAP-Client-ID als Push-Authentifizierungstoken-Zielgruppe 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. Zuerst muss Pub/Sub für den Nutzer oder das Dienstkonto, das den Aufruf „CreateSubscription“, „UpdateSubscription“ oder „ModifyPushConfig“ ausführt, eine Rolle mit der Berechtigung iam.serviceAccounts.actAs für das Push-Authentifizierungsdienstkonto haben. 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. Zum Erstellen des Tokens muss Pub/Sub einen internen Google-Dienst mit einer separaten Identität für das Signierungsdienstkonto aufrufen. Das ist das von Google verwaltete Dienstkonto service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com. Dieses Dienstkonto für die Signatur muss die Berechtigung iam.serviceAccounts.getOpenIdToken oder die Rolle Dienstkontoersteller (roles/iam.serviceAccountTokenCreator) für das Push-Authentifizierungsdienstkonto (oder eine 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, lautet der HTTP-Anfrageheader mit dem IAP-JWT x-goog-iap-jwt-assertion und muss entsprechend validiert werden. Weitere Informationen

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 postion 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();
        }

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"
    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 zu der 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 im Leitfaden für Google Log-in-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 von anderen Google Cloud-Diensten

Cloud Run, App Engine und Cloud Functions authentifizieren HTTP-Aufrufe aus Pub/Sub, indem Sie von Pub/Sub generierte Tokens prüfen. Die einzige erforderliche Konfiguration besteht darin, dem Aufrufer-Konto die erforderlichen IAM-Rollen zu gewähren.

Weitere Informationen findest du in den folgenden Leitfäden und Anleitungen für verschiedene Anwendungsfälle mit diesen Diensten:

Cloud Run:

Google App Engine:

Cloud Functions:

  • HTTP-Trigger: Ihr Push-Authentifizierungsdienstkonto 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 Pub/Sub-Trigger zum Aufrufen einer Funktion verwenden.

Zustellung der Nachricht 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.

Kontingente und Limits

Push-Abos unterliegen bestimmten Kontingenten und Ressourcenlimits.

Push-Backoff

Wenn ein Push-Abonnent negative Bestätigungen sendet, kann Pub/Sub Nachrichten mit einem Push-Backoff senden. Wenn Pub/Sub einen Push-Backoff verwendet, werden keine Nachrichten mehr für die Dauer von 100 Millisekunden bis 60 Sekunden zugestellt. Anschließend werden Nachrichten wieder zugestellt.

Der Push-Backoff ist ein exponentieller Backoff, der verhindert, dass ein Push-Abonnent Nachrichten empfängt, die er nicht verarbeiten kann. Wie lange Pub/Sub keine Nachrichten mehr sendet, hängt von der Anzahl negativer Bestätigungen ab, die Push-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 alle 30 bis 60 Sekunden Nachrichten.

Zustellungsrate

Pub/Sub passt die Anzahl der gleichzeitigen Push-Anfragen mithilfe eines Algorithmus für einen langsamen Start an. Die maximal zulässige Anzahl an gleichzeitigen Push-Anfragen ist das Push-Fenster. Das Push-Fenster erhöht sich bei jeder erfolgreichen Übermittlung und verringert sich bei jedem Fehler. Das System beginnt mit einem kleinen Fenster: dreimal N, wobei N die Anzahl der Veröffentlichungsregionen ist.

Wenn ein Abonnent Nachrichten bestätigt, wird das Fenster um bis zu 3.000 Mal ausstehende N-Nachrichten erhöht. Für Abos, bei denen mehr als 99 % der Nachrichten von den Abonnenten bestätigt werden und die durchschnittliche Latenz weniger als eine Sekunde beträgt, wird das Push-Fenster um bis zu 30.000 Mal ausstehende N-Nachrichten erhöht.

Die Latenz der Push-Anfrage umfasst Folgendes:

Nach 3.000 ausstehenden Nachrichten erhöht sich das Fenster linear, um zu verhindern, dass der Push-Endpunkt zu viele Nachrichten erhält. Wenn die durchschnittliche Latenz mehr als eine Sekunde beträgt oder der Abonnent weniger als 99 % der Anfragen bestätigt, sinkt 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.