firebase - 从 Firebase 函数调用 Google Play Developer API

标签 firebase google-api google-cloud-functions google-api-nodejs-client google-play-developer-api

我正在尝试开发一个服务器端验证我的用户的应用内购买和订阅为 recommended ,我想为此使用 Firebase 函数。基本上,它必须是一个 HTTP 触发函数,它接收购买 token ,调用 Play Developer API 来验证购买,然后对结果进行处理。

但是,调用许多 Google API(包括 Play Developer API )需要重要的授权。以下是我对所需设置的理解:

  • 必须有一个启用了 Google Play Developer API v2 的 GCP 项目。
  • 它应该是一个单独的项目,因为在 Google Play 控制台中只能有一个链接到 Play 商店。
  • 我的 Firebase Functions 项目必须以某种方式向该其他项目进行身份验证。我认为使用服务帐户最适合这种服务器到服务器的场景。
  • 最后,我的 Firebase Functions 代码必须以某种方式获取身份验证 token (希望是 JWT?),最后进行 API 调用以获取订阅状态。

  • 问题是绝对不存在人类可读的文档或指导。鉴于 Firebase 中的入口流量包含在免费计划中(所以我认为他们鼓励使用 Firebase Functions 中的 Google API),这一事实非常令人失望。我已经设法在这里和那里找到一些信息,但是对 Google API 的经验太少(其中大部分只需要使用 api key ),我需要帮助将它们组合在一起。

    到目前为止,这是我发现的:
  • 我有一个链接到 Play 商店并启用了 API 的 GCP 项目。但由于某种原因,尝试在 APIs Explorer 中对其进行测试会导致错误“用于调用 Google Play Developer API 的项目 ID 尚未在 Google Play Developer Console 中链接”。
  • 我创建了一个服务帐户并导出了一个 JSON key ,其中包含生成 JWT 的 key 。
  • 我还在 Play 管理中心为该服务帐户设置了读取权限。
  • 我找到了 Node.JS client library对于 Google API,它处于 alpha 阶段并且文档非常稀少(例如,没有关于如何使用 JWT 进行身份验证的明显文档,也没有关于如何调用 android 发布者 API 的示例)。目前我正在努力解决这个问题。不幸的是,我对阅读 JS 库代码不是很舒服,尤其是当编辑器不提供跳转到突出显示的函数源的可能性时。

  • 我很惊讶这没有被询问或记录,因为从 Firebase Functions 验证应用内购买似乎是一项常见任务。以前有没有人成功完成过,或者 Firebase 团队可能会介入回答?

    最佳答案

    我自己想通了。我还放弃了重量级的客户端库,只是手动编写了这几个请求。

    笔记:

  • 这同样适用于任何 Node.js 服务器环境。您仍然需要单独服务帐户的 key 文件来创建 JWT 和调用 API 的两个步骤,Firebase 也不异常(exception)。
  • 这同样适用于其他需要身份验证的 API — 不同之处仅在于 scope JWT 的字段。
  • a few APIs不需要您将 JWT 交换为访问 token — 您可以类型转换 JWT 并直接在 Authentication: Bearer 中提供它,无需往返 OAuth 后端。

  • 在您获得带有链接到 Play 商店的服务帐户的私钥的 JSON 文件后,调用 API 的代码如下所示(根据您的需要进行调整)。注意:我使用了 request-promise作为一种更好的方式 http.request .

    const functions = require('firebase-functions');
    const jwt = require('jsonwebtoken');
    const keyData = require('./key.json');         // Path to your JSON key file
    const request = require('request-promise');
    
    /** 
     * Exchanges the private key file for a temporary access token,
     * which is valid for 1 hour and can be reused for multiple requests
     */
    function getAccessToken(keyData) {
      // Create a JSON Web Token for the Service Account linked to Play Store
      const token = jwt.sign(
        { scope: 'https://www.googleapis.com/auth/androidpublisher' },
        keyData.private_key,
        {
          algorithm: 'RS256',
          expiresIn: '1h',
          issuer: keyData.client_email,
          subject: keyData.client_email,
          audience: 'https://www.googleapis.com/oauth2/v4/token'
        }
      );
    
      // Make a request to Google APIs OAuth backend to exchange it for an access token
      // Returns a promise
      return request.post({
        uri: 'https://www.googleapis.com/oauth2/v4/token',
        form: {
          'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
          'assertion': token
        },
        transform: body => JSON.parse(body).access_token
      });
    }
    
    /**
     * Makes a GET request to given URL with the access token
     */
    function makeApiRequest(url, accessToken) {
      return request.get({
        url: url,
        auth: {
          bearer: accessToken
        },
        transform: body => JSON.parse(body)
      });
    }
    
    // Our test function
    exports.testApi = functions.https.onRequest((req, res) => {
      // TODO: process the request, extract parameters, authenticate the user etc
    
      // The API url to call - edit this
      const url = `https://www.googleapis.com/androidpublisher/v2/applications/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}`;
    
      getAccessToken(keyData)
        .then(token => {
          return makeApiRequest(url, token);
        })
        .then(response => {
          // TODO: process the response, e.g. validate the purchase, set access claims to the user etc.
          res.send(response);
          return;
        })
        .catch(err => {
          res.status(500).send(err);
        });
    });
    

    These是我遵循的文档。

    关于firebase - 从 Firebase 函数调用 Google Play Developer API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49836166/

    相关文章:

    javascript - 从 Firebase 存储下载多个图像

    firebase - 从 firebase storage web - vuejs 下载图像

    python - GAE/Google API 刷新访问 token 时出现 DeadlineExceededErrors

    python - 如何将任何 Google API 服务对象传递给 App Engine 中的延迟任务?

    firebase - Cloud Functions for Firebase 的安全 HTTP 触发器

    javascript - 类型错误 : Cannot read property 'child' of undefined

    node.js - 检查用户是否从后端 Firebase 身份验证登录

    java - 使用 String[] args 参数作为 .setQ 参数中的变量 (Google Drive API V3)

    node.js - Google Cloud Platform - 使用 puppeteer (Node.js) 优化 Cloud Function

    ios - 我在哪里上传 APNS/p12 证书文件到 Firebase 控制台?