שילוב בצד השרת

בעלי תוכן דיגיטלי משתמשים בעיקר בשילוב בצד השרת כדי לנהל את הקוראים ואת . בעיקר, בעלי התוכן הדיגיטלי משתמשים ב-UpdateReaderEntitlements כדי לעדכן הרשומה של Google לגבי הרשאה מסוג 'מזהה מוצר' ל-PPID.

הגדרת 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 והפעלת ה-API עבור חשבון Google פרויקט בענן.

יצירה של חשבון שירות.

חשבונות שירות משמשים כדי לאפשר גישה מהאפליקציה Subscription Linking API.

  1. יוצרים חשבון שירות בתוך הפרויקט במסוף.
  2. יוצרים פרטי כניסה לחשבון השירות ומאחסנים את הקובץ credentials.json במיקום מאובטח שנגיש לאפליקציה שלכם.
  3. הקצאת התפקיד IAM 'אדמין לקישור מינויים' ל חשבון השירות שיצרתם. לשליטה פרטנית על היכולות של חשבון שירות, אפשר להקצות את התפקיד המתאים מהטבלה הבאה.
יכולת / תפקיד אדמין של קישור מינויים הרשאת צפייה בקישור מינויים בעל הרשאת צפייה בקישור מינויים
קבלת הרשאות לקוראים
מצרפים קוראים
עדכון הרשאות של קוראים
מחיקת הקוראים

שימוש בחשבונות שירות עם Subscription Linking API

להשתמש בחשבונות שירות כדי לאמת קריאות ל-Subscription Linking API, באמצעות ספריית הלקוח של googleapis או באמצעות חתימה על בקשות עם API ל-REST. ספריות לקוח מטפלות באופן אוטומטי בבקשות מתאים access_token, ואילו ב-API ל-REST נדרש אחזור של id_token ואז מחליפים אותו ב-access_token.

גם הלקוח הבא בדוגמאות של API ל-REST ולספרייה נעשה שימוש בנקודת הקצה getReader(). לשידור חי הדגמה של כל שיטות ה-API. אתר ההדגמה של קישור המינויים או הקוד שלו.

בקשה לדוגמה עם ספריית הלקוח של googleapis לצומת.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}`,
    requestBody
  });
};

חתימה ידנית על בקשות API ל-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
}