Abonnements Push

Dans le cadre de la distribution push, Pub/Sub lance des requêtes à votre application d'abonnés pour distribuer des messages.

Avant de commencer

Avant de lire ce document, veuillez prendre connaissance des points suivants:

  • Fonctionnement de Pub/Sub et des différents termes Pub/Sub

  • Les différents types d'abonnements compatibles avec Pub/Sub et les raisons pour lesquelles vous pourriez vouloir utiliser un abonnement push.

Propriétés d'un abonnement push

Lorsque vous configurez un abonnement push, vous pouvez spécifier les propriétés suivantes.

  • URL du point de terminaison (obligatoire) Adresse HTTPS accessible publiquement. Le serveur du point de terminaison push doit disposer d'un certificat SSL valide signé par une autorité de certification. Le service Pub/Sub envoie les messages aux points de terminaison push situés dans la région Google Cloud où le service stocke les messages. Le service Pub/Sub distribue les messages provenant de la même région Google Cloud de la manière la plus optimale possible.

    Pub/Sub ne nécessite plus de preuve de propriété pour les domaines d'URL d'abonnement push. Si votre domaine reçoit des requêtes POST inattendues de la part de Pub/Sub, vous pouvez signaler une suspicion d'abus.

  • Activez l'authentification. Lorsque cette option est activée, les messages distribués par Pub/Sub au point de terminaison push incluent un en-tête d'autorisation permettant au point de terminaison d'authentifier la requête. Des mécanismes d'authentification et d'autorisation automatiques sont disponibles pour les points de terminaison App Engine standards et Cloud Functions hébergés dans le même projet que l'abonnement.

    La configuration d'authentification d'un abonnement push authentifié comprend le compte de service et les paramètres d'audience spécifiés dans un appel create, patch ou ModifiedPushConfig:

    • Compte de service (obligatoire) Compte de service associé à l'abonnement push. Ce compte est utilisé comme revendication email du jeton Web JSON (JWT) généré. Voici la liste des conditions requises pour le compte de service:

    • Audience. Chaîne unique non sensible à la casse que le webhook utilise pour valider l'audience visée par ce jeton.

Abonnement push et VPC Service Controls

Vous ne pouvez pas créer d'abonnements push pour les projets protégés par VPC Service Controls, sauf si les points de terminaison push sont définis sur des services Cloud Run avec des URL run.app par défaut. Les domaines personnalisés ne fonctionnent pas.

Impossible de mettre à jour les abonnements push existants pour les projets protégés par VPC Service Controls. Les abonnements push existants continuent de fonctionner, même s'ils ne sont pas protégés par VPC Service Controls.

Recevoir des messages

Lorsque Pub/Sub transmet un message à un point de terminaison push, il envoie le message dans le corps d'une requête POST. Le corps de la requête est un objet JSON et les données du message se trouvent dans le champ message.data. Les données du message sont encodées en base64.

L'exemple suivant est le corps d'une requête POST envoyée à un point de terminaison push :

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

Pour recevoir des messages d'abonnements push, utilisez un webhook et traitez les requêtes POST envoyées par Pub/Sub au point de terminaison push. Pour en savoir plus sur le traitement de ces requêtes POST dans App Engine, consultez la page Écrire des messages Pub/Sub et y répondre.

Après avoir reçu une requête push, renvoyez un code d'état HTTP. Pour accuser réception du message, renvoyez l'un des codes d'état suivants :

  • 102
  • 200
  • 201
  • 202
  • 204

Pour envoyer un accusé de réception négatif pour le message, renvoyez tout autre code d'état. Si vous envoyez un accusé de réception négatif ou que le délai de confirmation arrive à expiration, Pub/Sub renvoie le message. Vous ne pouvez pas modifier le délai d'accusé de réception des messages individuels que vous recevez des abonnements push.

Authentification pour l'abonnement push

Si un abonnement push utilise l'authentification, le service Pub/Sub signe un jeton JWT et l'envoie dans l'en-tête d'autorisation de la requête push. Le jeton JWT inclut des revendications et une signature.

Les abonnés peuvent valider le JWT et vérifier les éléments suivants:

  • Les revendications sont exactes.
  • Le service Pub/Sub a signé les revendications.

Si les abonnés utilisent un pare-feu, ils ne peuvent pas recevoir de requêtes push. Pour recevoir des requêtes push, vous devez désactiver le pare-feu et vérifier le jeton JWT.

Format JWT

Le jeton JWT est un jeton JWT OpenIDConnect composé d'un en-tête, d'un ensemble de revendications et d'une signature. Le service Pub/Sub encode le jeton JWT en tant que chaîne en base64 avec des délimiteurs de points.

Par exemple, l'en-tête d'autorisation suivant inclut un jeton JWT encodé :

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

L'en-tête et l'ensemble de revendications sont des chaînes JSON. Une fois décodés, ils prennent la forme suivante :

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

Les jetons associés aux requêtes envoyées aux points de terminaison push peuvent remonter jusqu'à une heure.

Configurer Pub/Sub pour l'authentification push

L'exemple suivant montre comment définir le compte de service d'authentification push sur le compte de service de votre choix et comment attribuer le rôle iam.serviceAccountTokenCreator au compte de service géré par Googleservice-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com.

Console

  1. Accédez à la page Abonnements Pub/Sub.

    Accéder à la page Abonnements

  2. Cliquez sur Créer un abonnement.

  3. Dans le champ ID d'abonnement, saisissez un nom.

  4. Sélectionnez un thème.

  5. Sélectionnez Push comme type de diffusion.

  6. Saisissez une URL de point de terminaison.

  7. Cochez Activer l'authentification.

  8. Sélectionnez un compte de service.

  9. Facultatif: Cliquez sur Accorder pour attribuer au compte de service géré par Google service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com le rôle iam.serviceAccountTokenCreator s'il ne dispose pas déjà du rôle.

  10. Facultatif: saisissez une audience.

  11. Cliquez sur Créer.

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'

Si vous utilisez un abonnement push authentifié avec une application App Engine sécurisée avec Identity-Aware Proxy, vous devez fournir l'ID client IAP en tant qu'audience de jeton d'authentification push. Pour activer IAP sur votre application App Engine, consultez la page Activer IAP. Pour trouver l'ID client IAP, recherchez l'ID client IAP-App-Engine-app sur la page Identifiants.

Revendications

Un jeton JWT peut être utilisé pour valider que les revendications (y compris les revendications par email et aud) sont signées par Google. Pour plus d'informations sur la manière dont les API OAuth 2.0 de Google peuvent être utilisées à la fois pour l'authentification et l'autorisation, consultez la documentation sur OpenID Connect.

Deux mécanismes rendent ces revendications significatives. Tout d'abord, Pub/Sub nécessite que l'utilisateur ou le compte de service effectuant l'appel CreateSubscription, UpdateSubscription ou ModifierPushConfig dispose d'un rôle doté de l'autorisation iam.serviceAccounts.actAs sur le compte de service d'authentification push. Un rôle de ce type est le rôle roles/iam.serviceAccountUser.

Deuxièmement, l'accès aux certificats utilisés pour signer les jetons est étroitement contrôlé. Pour créer le jeton, Pub/Sub doit appeler un service Google interne à l'aide d'une identité de compte de service de signature distincte, à savoir le compte de service géré par Google service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com. Ce compte de service de signature doit disposer de l'autorisation iam.serviceAccounts.getOpenIdToken ou du rôle Créateur de jetons du compte de service (roles/iam.serviceAccountTokenCreator) sur le compte de service d'authentification push (ou sur toute ressource ancêtre, telle que le projet) du compte de service d'authentification push.

Valider les jetons

La validation des jetons envoyés par Pub/Sub au point de terminaison push implique les actions suivantes :

  • Vérifier l'intégrité du jeton à l'aide de la validation de signature
  • S'assurer que les revendications email et audience du jeton correspondent aux valeurs définies dans la configuration de l'abonnement push.

L'exemple suivant montre comment authentifier une requête push auprès d'une application App Engine non sécurisée avec Identity-Aware Proxy. Si votre application App Engine est sécurisée par IAP, l'en-tête de requête HTTP contenant le JWT IAP est x-goog-iap-jwt-assertion et doit être validé en conséquence.

protocol

Requête :

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

Réponse :

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#

Avant d'essayer cet exemple, suivez les instructions d'installation dans le langage C# qui se trouvent sur la page Démarrage rapide : utiliser des bibliothèques clientes. Pour en savoir plus, consultez la documentation de référence sur l'API Pub/Sub pour C#.

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

Accéder

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

Pour en savoir plus sur la variable d'environnement PUBSUB_VERIFICATION_TOKEN utilisée dans les exemples de code ci-dessus, consultez la page Écrire des messages Pub/Sub et y répondre.

Consultez d'autres exemples sur la validation du support JWT dans le guide de connexion à Google pour les sites Web. Une présentation plus complète des jetons OpenID est disponible dans le guide OpenID Connect, et comprend une liste de bibliothèques clientes qui utiles pour valider les jetons JWT.

Authentification à partir d'autres services Google Cloud

Cloud Run, App Engine et Cloud Functions authentifient les appels HTTP à partir de Pub/Sub en validant les jetons générés par Pub/Sub. La seule configuration requise consiste à attribuer les rôles IAM nécessaires au compte de l'appelant.

Consultez les guides et tutoriels suivants pour différents cas d'utilisation avec ces services:

Cloud Run:

Google App Engine :

Cloud Functions:

  • Déclencheurs HTTP : votre compte de service d'authentification push doit disposer du rôle roles/cloudfunctions.invoker pour appeler une fonction si vous avez l'intention d'utiliser des requêtes push Pub/Sub en tant que déclencheurs HTTP pour la fonction.
  • Déclencheurs Google Cloud Pub/Sub : les rôles et les autorisations IAM sont configurés automatiquement si vous utilisez des déclencheurs Pub/Sub pour appeler une fonction.

Arrêter et reprendre la distribution des messages

Pour empêcher temporairement l'envoi de requêtes par Pub/Sub au point de terminaison push, passez l'abonnement en mode pull. Le changement peut prendre plusieurs minutes.

Pour reprendre la distribution push, définissez à nouveau l'URL sur un point de terminaison valide. Pour arrêter définitivement la distribution, supprimez l'abonnement.

Quotas et limites

Les abonnements push sont soumis à un ensemble de quotas et de limites de ressources.

Intervalle entre les tentatives d'envoi push

Si un abonné push envoie des accusés de réception négatifs, Pub/Sub peut distribuer des messages à l'aide d'un intervalle de réponse. Lorsque Pub/Sub utilise un intervalle push, il cesse de diffuser les messages pendant 100 millisecondes à 60 secondes, puis recommence à les diffuser.

L'intervalle push est un intervalle exponentiel qui empêche un abonné push de recevoir des messages qu'il ne peut pas traiter. La durée pendant laquelle Pub/Sub cesse de diffuser des messages dépend du nombre d'accusés de réception négatifs envoyés par les abonnés push.

Par exemple, si un abonné push reçoit cinq messages par seconde et envoie un accusé de réception négatif par seconde, Pub/Sub diffuse des messages toutes les 500 millisecondes environ. Si l'abonné push envoie cinq accusés de réception négatifs par seconde, Pub/Sub diffuse des messages toutes les 30 à 60 secondes.

Rythme de distribution

Pub/Sub ajuste le nombre de requêtes push simultanées à l'aide d'un algorithme de démarrage progressif (Slow Start). Le nombre maximal autorisé de requêtes push simultanées correspond à la fenêtre push. La fenêtre push augmente pour toute distribution réussie et diminue pour tout échec. Le système commence par une petite fenêtre : trois fois N, N étant le nombre de régions de publication.

Lorsqu'un abonné accuse réception des messages, la fenêtre augmente de manière exponentielle jusqu'à 3 000 fois N messages en attente. Pour les abonnements dont les abonnés accusent réception de plus de 99 % des messages avec une latence moyenne des requêtes push inférieure à une seconde, la fenêtre d'envoi augmente jusqu'à 30 000 fois N messages en attente.

La latence des requêtes push inclut les éléments suivants :

Après 3 000 messages en attente, la fenêtre augmente de façon linéaire pour éviter que le point de terminaison push ne reçoive trop de messages. Si la latence moyenne dépasse une seconde ou si l'abonné accuse réception de moins de 99 % des requêtes, la fenêtre se réduit à la limite inférieure de 3 000 messages en attente.

Pour plus d'informations sur les métriques que vous pouvez utiliser pour surveiller la diffusion push, consultez la section Surveiller les abonnements push.