Cómo sincronizar los derechos de los usuarios (integración del servidor)

Los editores usan principalmente la integración del servidor para administrar a los lectores y sus derechos. Ante todo, usan UpdateReaderEntitlements para actualizar el registro de Google del derecho de un ID del producto para un PPID.

Configuración de Google Cloud

La configuración de Subscription Linking en Google Cloud incluye dos componentes principales:

  1. La habilitación de la API para un proyecto determinado
  2. La creación de una cuenta de servicio para acceder a la API

Cómo habilitar la API de Subscription Linking

Para usar una cuenta de servicio y administrar los derechos de un lector, un proyecto de Google Cloud debe tener habilitada la API de Subscription Linking y una cuenta de servicio de OAuth configurada correctamente. Para habilitar la API de Subscription Linking para un proyecto, navega desde el menú -> APIs y servicios -> Biblioteca y busca Subscription Linking, o visita la página directamente:


https://console.cloud.google.com/apis/library?project=gcp_project_id

API

Figura 1: Navegación a la biblioteca de la API y habilitación de la API para un proyecto de Google Cloud

Cómo crear una cuenta de servicio

Las cuentas de servicio se usan para permitir el acceso de tu aplicación a la API de Subscription Linking.

  1. Crea una cuenta de servicio desde la consola de tu proyecto.
  2. Crea credenciales para la cuenta de servicio y almacena el archivo credentials.json en una ubicación segura a la que pueda acceder tu aplicación.
  3. Otorga el rol de IAM de "Administrador de vinculaciones de suscripciones" a la cuenta de servicio que creaste. Para un control detallado de las capacidades de la cuenta de servicio, puedes asignar el rol correspondiente desde la siguiente tabla:
Capacidad/rol Administrador de vinculaciones de suscripciones Visualizador de vinculaciones de suscripciones Visualizador de derechos de vinculaciones de suscripciones
Obtener derechos de lector
Obtener lectores
Actualizar derechos de lector
Borrar lectores

Cómo usar cuentas de servicio con la API de Subscription Linking

Usa cuentas de servicio para autenticar llamadas a la API de Subscription Linking, ya sea con la biblioteca cliente de googleapis o firmando solicitudes con la API de REST. Las bibliotecas cliente controlan automáticamente la solicitud del access_token apropiado, mientras que la API de REST requiere que se recupere un id_token y, luego, se lo intercambie por un access_token.

Los siguientes ejemplos de biblioteca cliente y API de REST usan el extremo getReader(). Para ver una demostración en vivo de todos los métodos de la API, consulta el sitio Demostración de Subscription Linking o su código.

Solicitud de muestra con la biblioteca cliente de googleapis node.js

import {readerrevenuesubscriptionlinking_v1, Auth} from 'googleapis';
const subscriptionLinking = readerrevenuesubscriptionlinking_v1.Readerrevenuesubscriptionlinking;

class SubscriptionLinking {
  constructor() {
    this.auth = new Auth.GoogleAuth({
      keyFile: process.env.KEY_FILE,
      scopes: [
        'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
      ],
    })
  }

  init() {
    return new subscriptionLinking(
        {version: 'v1', auth: this.auth})
  }
}

const api = new SubscriptionLinking();
const client = api.init();

async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.get({
    name: `publications/${publicationId}/readers/${ppid}`,
  });
};

async function updateEntitlements(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  const requestBody = {
    /*
    Refer to
    https://developers.google.com/news/subscribe/subscription-linking/appendix/glossary#entitlements_object
    */
    entitlements : [{
      product_id: `${publicationId}:basic`,
      subscription_token: 'abc1234',
      detail: 'This is our basic plan',
      expire_time: '2025-10-21T03:05:08.200564Z'
    }]
  };
  return await client.publications.readers.updateEntitlements({
    name: `publications/${publicationId}/readers/${ppid}/entitlements`,
    requestBody
  });
};

Firma manual de la solicitud a la API de REST

import fetch from 'node-fetch'
import jwt from 'jsonwebtoken'

function getSignedJwt() {
  /*
    Either store the credentials string in an environmental variable
    Or implement logic to fetch it.
  */
  const key_file = process.env.CREDENTIALS_STRING

  const issueDate = new Date()
  const expireMinutes = 60
  const offsetInSeconds = issueDate.getTimezoneOffset() * 60000
  const expireDate = new Date(issueDate.getTime() + (expireMinutes * 60000))
  const iat = Math.floor((issueDate.getTime() + offsetInSeconds) / 1000)
  const exp = Math.floor((expireDate.getTime() + offsetInSeconds) / 1000)

  const token = {
    iss: key_file.client_email,
    iat,
    exp,
    aud: 'https://oauth2.googleapis.com/token',
    scope:'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage',
  }
  return jwt.sign(token, key_file.private_key, {
    algorithm: 'RS256',
    keyid: key_file.private_key_id,
  })
}

async function getAccessToken(signedJwt) {
  let body = new URLSearchParams();
  body.set('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer')
  body.set('assertion', signedJwt)
  const request = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body
  })

  const accessResponse = await accessFetch.json()
  return accessResponse.access_token
}

async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID
  const base_url = 'https://readerrevenuesubscriptionlinking.googleapis.com/v1'
  const endpoint = `${base_url}/publications/${publicationId}/readers/${ppid}`
  const signedJwt = await getSignedJwt()
  const accessToken = await getAccessToken(signedJwt)

  const reader = await fetch(endpoint, {
     method: 'GET',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   }).then((response) => {
    return response.json()
  })

  return reader
}