代码之家  ›  专栏  ›  技术社区  ›  0xC0DED00D

使用默认凭据访问Google工作表

  •  5
  • 0xC0DED00D  · 技术社区  · 6 年前

    我在谷歌表单上有一些数据。我正在使用 Sheets API for Node.js 访问此数据。对于身份验证,我使用服务帐户JSON生成一个JWTClient。

    我可以访问来自sheets api的数据,一切正常。代码位于 Google App Engine Flexible environment 。它在本地主机和GAE上都可以正常工作。

    唯一的问题是,我需要提供用于身份验证的服务帐户密钥json。这在本地环境中很好,但在应用程序引擎上,它提供了 default credential 对于服务帐户(我使用相同的服务帐户)。所以我认为我不应该手动提供凭据,而应该让GAE负责服务器上的凭据。

    但它不会自动进行身份验证,仍然是一个身份验证参数。

    下面是我当前对sheets api的实现-

    const { promisify } = require('util');
    const google = require('googleapis');
    const auth = require('./auth');
    const credentials = require('../configs/credentials');
    
    const sheets = google.sheets('v4');
    const getSheetValuesAsync = promisify(sheets.spreadsheets.values.get);
    //region private
    function readSheet(params) {
      return getSheetValuesAsync(params);
    }
    //endregion private
    
    //region public
    async function get(sheetConfigName) {
      const sheetConfig = credentials.sheets[sheetConfigName];
      //This is theJWTClient which authenticates the api request currently.
      //I want to remove this
      const authClient = await auth.authorizeWithServiceAccount('serviceAccountName', [
        'https://www.googleapis.com/auth/spreadsheets.readonly'
      ]);
      console.log('Client received');
      let params = {
        auth: authClient, //I tried removing this parameter, but it didn't work
        spreadsheetId: sheetConfig.id,
        range: 'A:M'
      };
      let data = await readSheet(params);
      return data;
    }
    //endregion public
    module.exports = {
      get: get
    };
    

    我得到的错误如下:-

    {
      code:403,
      message: 'The request is missing a valid API key.
    }
    

    我有设置 GOOGLE_APPLICATION_CREDENTIALS 本地环境的环境变量已经适用于google云API,但不适用于工作表。

    也是这样 Application Default Credentials 仅针对谷歌云API,或者可以与Sheets API或任何其他驱动器API一起使用?如果它也可以与驱动器API一起使用,那么如何实现呢?

    3 回复  |  直到 6 年前
        1
  •  1
  •   Ying Li    6 年前

    如果要使用Google Sheets API,需要提供OAuth服务帐户,如 documentation 。默认服务帐户主要用于从GCP(谷歌云平台)中提取数据。因此,您的计算引擎可以访问您的云数据存储,或者如果您的应用引擎可以访问您的云存储。

    默认服务帐户没有客户端机密JSON,这是Sheets API所需要的。

    或者,如果要使用 Google Sheets REST API

        2
  •  1
  •   LundinCast    6 年前

    Google云服务帐户旨在访问云API,不能被授予Sheets API的适当范围。

    由于App Engine Flexible应用程序在计算引擎VM上运行,因此可以通过如下方式查询元数据服务器来获取默认服务帐户的令牌:

    > curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" -H "Metadata-Flavor: Google"
    

    但是,调用提供该标记的Sheets API时,会出现以下错误:

    {
      "error": {
        "code": 403,
        "message": "Request had insufficient authentication scopes.",
        "status": "PERMISSION_DENIED"
      }
    }
    

    我相信您需要为您的用例使用API密钥。

        3
  •  1
  •   0xC0DED00D    6 年前

    在谷歌节点的最新更新中。js客户端包(28.x),他们有了一种新的方法来获取authClient,而不需要第二个包。这是怎么做的-

    const { google } = require('googleapis');
      const authClient = await google.auth.getClient({
      credentials: credentials,
      scopes: scopes
    });
    

    credentials 只是服务帐户JSON对象。最好的部分是,如果您不提供该属性,它将检查 GOOGLE_APPLICATION_CREDENTIALS 环境变量,该变量将具有服务帐户密钥JSON的绝对路径,并自动将其考虑用于身份验证。
    您可以使用生成的authClient为google sheets API设置auth参数,方法如下-

    首先,当您想为不同的API调用提供不同的身份验证时。

    const { google } = require('googleapis');
    const sheets = google.sheets('v4');
    sheets.spreadsheets.values.getAsync = promisify(sheets.spreadsheets.values.get);
    sheets.spreadsheets.values.getAsync({
        auth: authClient,
        spreadsheetId: spreadsheetId,
        range: range
      });
    

    也可以直接向sheets对象提供身份验证。该对象上的所有API调用都将使用相同的authClient,并且不需要auth参数。

    const sheets = google.sheets({version:'v4',auth:authClient);
    

    最好的方法是为所有Google API调用设置auth默认值,这样就不必向任何sheets对象或API调用传递authClient。

    google.options({
      auth: authClient
    });
    

    如果您计划对不同的API使用不同的服务帐户,您仍然可以在sheets(或drive或任何其他对象)API对象中重写auth参数,也可以重写任何API调用。

    对于在本地进行的测试,您始终可以设置环境路径,这样您实际上就不必将服务帐户传递给 google.auth 对象我是这样做的

    let resolve = require('path').resolve;
    if (process.env.NODE_ENV === 'production') {
      //Set config based on production environment. It won't be set in local environment, unless you specially set it.
    } else if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
      process.env.GOOGLE_APPLICATION_CREDENTIALS = resolve(
          './relative/path/to/the/json/key.json'
      ); //resolve will just convert relative path to the absolute path.
    }