Интеграция на стороне сервера

Издатели в основном используют интеграцию на стороне сервера для управления читателями и их правами. В первую очередь издатели используют UpdateReaderEntitlements для обновления записи Google о разрешении идентификатора продукта для PPID.

Настройка Google Cloud

Настройка привязки подписки в Google Cloud включает два основных компонента:

  1. Включение API для данного проекта
  2. Создание сервисной учетной записи для доступа к API

Включите API привязки подписки

Чтобы использовать учетную запись службы и управлять правами читателя, в проекте Google Cloud должен быть включен API привязки подписки и правильно настроенная учетная запись службы OAuth. Чтобы включить API привязки подписки для проекта, перейдите в меню -> API и службы -> Библиотека и найдите Subscription Linking или посетите страницу напрямую:


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

api

Рисунок 1. Переход к библиотеке API и включение API для проекта Google Cloud.

Создать учетную запись службы

Учетные записи служб используются для разрешения доступа вашего приложения к API привязки подписки.

  1. Создайте учетную запись службы в консоли вашего проекта.
  2. Создайте учетные данные для учетной записи службы и сохраните файл credentials.json в безопасном месте, доступном для вашего приложения.
  3. Предоставьте роль IAM «Администратор привязки подписки» созданному вами сервисному аккаунту. Для детального контроля над возможностями учетной записи службы вы можете назначить соответствующую роль из следующей таблицы.
Возможности/Роль Администратор привязки подписки Средство просмотра привязки подписки Средство просмотра прав на привязку подписки
Получите права читателя
Получить читателей
Обновить права читателя
Удалить читателей

Используйте сервисные учетные записи с API привязки подписки.

Используйте учетные записи служб для аутентификации вызовов API связывания подписки либо с помощью клиентской библиотеки googleapis , либо путем подписания запросов с помощью REST API. Клиентские библиотеки автоматически обрабатывают запрос соответствующего access_token , тогда как REST API требует получения id_token и последующего обмена его на access_token .

И в следующей клиентской библиотеке, и в примерах REST API используется конечная точка getReader() . Демонстрацию всех методов API в реальном времени см. на сайте демонстрации привязки подписки или его коде .

Пример запроса с клиентской библиотекой 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}`,
  })
}

Подписание запросов REST API вручную.

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
}