服务器端集成

发布商主要使用服务器端集成来管理读者及其使用权。主要而言,发布商会使用 UpdateReaderEntitlements 来更新 Google 对 PPID 的产品 ID 使用权记录。

Google Cloud 设置

在 Google Cloud 中配置订阅关联包括两个主要部分:

  1. 为给定项目启用 API
  2. 创建用于访问 API 的服务帐号

启用 Subscription Linking API

如需使用服务帐号并管理读者的权限,Google Cloud 项目必须同时启用 Subscription Linking API 和正确配置的 OAuth 服务帐号。如需为项目启用 Subscription Linking API,请依次选择“菜单”->“API 和服务”->“库”,然后搜索 Subscription Linking,或直接访问该页面:


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

api

图 1. 导航到 API 库,并为 Google Cloud 项目启用该 API。

创建服务账号

服务帐号用于允许您的应用访问 Subscription Linking API。

  1. 在项目的控制台中创建服务帐号
  2. 为服务帐号创建凭据,并将 credentials.json 文件存储在您的应用可以访问的安全位置。
  3. 向您创建的服务帐号授予 IAM 角色“Subscription Linking Admin”。如需精细控制服务帐号的功能,您可以分配下表中的相应角色。
能力 / 角色 Subscription Linking Admin Subscription Linking Viewer Subscription Linking Entitlements Viewer
获取读者权益
吸引读者
更新读者使用权
删除读者

将服务帐号与 Subscription Linking API 搭配使用

通过 googleapis 客户端库或 REST API 对请求签名,使用服务帐号对 Subscription Linking API 的调用进行身份验证。客户端库会自动处理请求适当的 access_token 的操作,而 REST API 需要检索 id_token,然后将其交换为 access_token

以下客户端库和 REST API 示例都使用 getReader() 端点。如需查看所有 API 方法的实时演示,请参阅订阅关联演示网站或其代码

使用 node.js googleapis 客户端库的示例请求

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
}