ซิงค์การให้สิทธิ์ของผู้ใช้ (การผสานรวมฝั่งเซิร์ฟเวอร์)

ผู้เผยแพร่โฆษณาใช้การผสานรวมฝั่งเซิร์ฟเวอร์เป็นหลักในการจัดการผู้อ่านและสิทธิ์ของผู้อ่าน โดยทั่วไปแล้ว ผู้เผยแพร่โฆษณาจะใช้ UpdateReaderEntitlements เพื่ออัปเดตระเบียนสิทธิ์การใช้รหัสผลิตภัณฑ์ของ Google สำหรับ PPID

การตั้งค่า Google Cloud

การกําหนดค่าการลิงก์การสมัครใช้บริการใน Google Cloud ประกอบด้วยคอมโพเนนต์หลัก 2 อย่าง ได้แก่

  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 Cloud

สร้างบัญชีบริการ

ระบบจะใช้บัญชีบริการเพื่ออนุญาตให้แอปพลิเคชันเข้าถึง Subscription Linking API

  1. สร้างบัญชีบริการภายในคอนโซลของโปรเจ็กต์
  2. สร้างข้อมูลเข้าสู่ระบบสําหรับบัญชีบริการ และจัดเก็บไฟล์ credentials.json ไว้ในตําแหน่งปลอดภัยที่แอปพลิเคชันเข้าถึงได้
  3. มอบบทบาท IAM "ผู้ดูแลการลิงก์การสมัครใช้บริการ" ให้กับบัญชีบริการที่คุณสร้างขึ้น หากต้องการควบคุมความสามารถของบัญชีบริการอย่างละเอียด คุณสามารถมอบหมายบทบาทที่เหมาะสมจากตารางต่อไปนี้
ความสามารถ / บทบาท ผู้ดูแลการลิงก์การสมัครใช้บริการ ผู้ดูการลิงก์การสมัครใช้บริการ ผู้ดูการให้สิทธิ์การลิงก์การสมัครใช้บริการ
รับการให้สิทธิ์ผู้อ่าน
ดึงดูดผู้อ่าน
อัปเดตการให้สิทธิ์แก่ผู้อ่าน
ลบผู้อ่าน

ใช้บัญชีบริการกับ Subscription Linking API

หากต้องการตรวจสอบสิทธิ์การเรียก Subscription Linking API ด้วยบัญชีบริการ ให้ใช้ไลบรารีไคลเอ็นต์ googleapis (ซึ่งจัดการคําขอ access_token โดยอัตโนมัติ) หรือลงชื่อขอกับ REST API โดยตรง หากใช้ REST API ก่อนอื่นคุณต้องได้รับ access_token (ผ่านไลบรารี Google Auth หรือใช้ JWT ของบัญชีบริการ) แล้วใส่ไว้ในส่วนหัว Authorization

ทั้งตัวอย่างไลบรารีไคลเอ็นต์และ REST API ต่อไปนี้มีโค้ดตัวอย่างสำหรับวิธีเรียก getReader(), getReaderEntitlements(), updateReaderEntitlements() และ deleteReader()

ไลบรารีของไคลเอ็นต์

ส่วนนี้จะอธิบายวิธีใช้ไลบรารีไคลเอ็นต์ googleapis ใน Node.js

ตัวอย่างคำขอ

สําหรับช่อง keyFile ในคอนสตรคเตอร์ Auth.GoogleAuth ให้ตั้งค่าเส้นทางไปยังคีย์บัญชีบริการ หากส่งออกคีย์บัญชีบริการไม่ได้เนื่องจากนโยบายขององค์กร คุณจะใช้วิธีการข้อมูลเข้าสู่ระบบเริ่มต้นของบัญชี (ADC) ได้ หากใช้วิธีการ ADC คุณไม่จําเป็นต้องระบุkeyFile ช่อง เนื่องจาก ADC จะค้นหาข้อมูลเข้าสู่ระบบด้วยตัวเอง

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 subscriptionLinkingApi = new SubscriptionLinking();
const client = subscriptionLinkingApi.init();

/**
 * Retrieves details for a specific reader associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {Promise<object>} A promise that resolves with the reader's details
 *  from the API.
 */
async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.get({
    name: `publications/${publicationId}/readers/${ppid}`,
  });
};

/**
 * Updates the entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader whose
 *  entitlements are being updated.
 * @return {Promise<object>} A promise that resolves with the result of the
 *  updated entitlements object.
 */
async function updateReaderEntitlements(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
  });
};

/**
 * Retrieves the current entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {Promise<object>} A promise that resolves with the reader's entitlements object.
 */
async function getReaderEntitlements(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.getEntitlements({
    name: `publications/${publicationId}/readers/${ppid}/entitlements`
  });
};

/**
 * Deletes a specific Subscription Linkikng reader record associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader to be deleted.
 * @param {boolean=} forceDelete - If true, delete the user even if their
 *  entitelements are not empty
 * @return {Promise<object>} A promise that resolves upon successful deletion
 *  with an empty object ({})
 */
async function deleteReader(ppid, forceDelete = false) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.delete({
    name: `publications/${publicationId}/readers/${ppid}`
    force: forceDelete
  });
};

REST API

หากต้องการเรียกใช้ปลายทาง REST API คุณสามารถใช้วิธีการใดก็ได้เพื่อรับ accessToken เพื่อตั้งค่าส่วนหัว Authorization

1. ใช้ไลบรารี GoogleAuth

สำหรับคีย์ credentials คุณสามารถใช้คีย์บัญชีบริการหรือข้อมูลเข้าสู่ระบบเริ่มต้นของบัญชี (ADC) หากใช้วิธีการ ADC คุณไม่จําเป็นต้องระบุช่อง credentials เนื่องจาก ADC จะค้นหาข้อมูลเข้าสู่ระบบด้วยตนเอง

import { GoogleAuth } from 'google-auth-library';
import credentialJson from 'path_to_your_json_file' with { type: 'json' };

const auth = new GoogleAuth({
    credentials: credential_json,
    scopes: [
      'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
    ]
});

async function getAccessToken() {
    const accessToken = await auth.getAccessToken();
    return accessToken;
}

2. สร้าง access_token โดยใช้ JWT ของบัญชีบริการ

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

function getSignedJwt() {
  /*
    Either store the service account 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 response = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body
  })
  const accessResponse = await response.json();
  return accessResponse.access_token;
}

ตัวอย่างโค้ดสําหรับการเรียก REST API ด้วยไลบรารี Google Auth

import { GoogleAuth } from 'google-auth-library';
import fetch from 'node-fetch'
import credentialJson from 'path_to_your_json_file' with { type: 'json' };

const BASE_SUBSCRIPTION_LINIING_API_URL='https://readerrevenuesubscriptionlinking.googleapis.com/v1';
const publicationId = process.env.PUBLICATION_ID

const auth = new GoogleAuth({
    credentials: credentialJson,
    scopes: [
      'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
    ]
});

async function getAccessToken() {
    const accessToken = await auth.getAccessToken();
    return accessToken;
}

/**
 * Retrieves details for a specific reader associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {object} reader json for the given ppid
 */
async function getReader(ppid) {
  const endpoint = `${BASE_SUBSCRIPTION_LINIING_API_URL}/publications/${publicationId}/readers/${ppid}`;
  const accessToken = await getAccessToken();
  const response = await fetch(endpoint, {
     method: 'GET',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   });
  const reader = await response.json();
  return reader;
}

/**
 * Updates the entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {object} the updated entitlements object in json.
 */
async function updateReaderEntitlements(ppid) {
  const endpoint = `${BASE_SUBSCRIPTION_LINIING_API_URL}/publications/${publicationId}/readers/${ppid}/entitlements`;
  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'
    }]
  };
  const response = await fetch(endpoint, {
     method: 'PATCH',
     headers: {
       Authorization: `Bearer ${accessToken}`,
       'Content-Type': 'application/json',
     },
     body: JSON.stringify(requestBody)
   })
  const updatedEntitlements = await response.json();
  return updatedEntitlements;
}

/**
 * Retrieves the current entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {object} the reader's entitlements object in json.
 */
async function getReaderEntitlements(ppid) {
  const endpoint = `${BASE_SUBSCRIPTION_LINIING_API_URL}/publications/${publicationId}/readers/${ppid}/entitlements`;
  const accessToken = await getAccessToken();
  const response = await fetch(endpoint, {
     method: 'GET',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   });
  const entitlements = await response.json();
  return entitlements;
}

/**
 * Deletes a specific Subscription Linkikng reader record associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @param {boolean=} forceDelete - If true, delete the user even if their
 *  entitelements are not empty
 * @return {object} returns an empty object ({}) if the delete operation is successful
 */
async function deleteReader(ppid, forceDelete = false) {
  const endpoint = `${BASE_SUBSCRIPTION_LINIING_API_URL}/publications/${publicationId}/readers/${ppid}?force=${forceDelete}`;
  const response = await fetch(endpoint, {
     method: 'DELETE',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     }
   });
  const result = await response.json();
  return result;
}