【问题标题】:Using default credentials for accessing Google Sheets使用默认凭据访问 Google 表格
【发布时间】:2018-09-08 20:31:36
【问题描述】:

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

我可以从 sheet api 访问数据,一切正常。代码托管在Google App Engine Flexible environment。它适用于本地主机和 GAE。

唯一的问题是我需要提供服务帐户密钥 json 进行身份验证。这在本地环境中很好,但在 App Engine 上它为服务帐户提供了一个default credential(我使用的是相同的服务帐户)。所以我认为我不应该手动提供凭据,让 GAE 处理服务器上的凭据。

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

这是我当前对工作表 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-cloud API,但不适用于工作表。

Application Default Credentials 是仅用于 google-cloud API 还是可以与 Sheets API 或任何其他 Drive API 一起使用?如果它也可以与驱动器 API 一起使用,那该怎么做?

【问题讨论】:

  • 您是否与服务帐户共享了工作表?
  • @LundinCast 该工作表具有公共访问权限,因此不是必需的。
  • 那么您可以使用 API 密钥。还是需要使用 OAuth 2.0?
  • 是的,我可以使用 API 密钥,它也可以使用它。我的目标是尽量减少代码中的额外凭据。我不想在代码中包含 API 密钥或服务帐户。由于服务帐户已经可用且易于管理,我想使用同一个帐户。多个凭据很难管理。

标签: javascript node.js google-app-engine google-cloud-platform google-sheets-api


【解决方案1】:

如果您想使用 Google Sheets API,您需要提供一个 OAuth 服务帐户,如 documentation 中所示。默认服务帐户主要用于从 GCP(谷歌云平台)中提取数据时使用。因此,您的 Compute Engine 可以访问您的 Cloud Datastore,或者您的 App Engine 是否可以访问您的 Cloud Storage。

默认服务帐号没有 Sheets API 需要的客户端密钥 JSON。

或者,如果您想使用Google Sheets REST API,您可以使用公共文档的 API 密钥。

【讨论】:

  • “默认服务帐户没有客户端密钥 JSON,这是 Sheets API 所需要的。” - 我认为确实如此,至少这是我在本地机器上设置的。我没有尝试在 GCE 或 GAE 上阅读,但我想它们也必须设置,否则服务帐户将如何进行身份验证?
【解决方案2】:

Google Cloud 服务帐号旨在访问 Cloud API,无法被授予 Sheets API 的适当范围。

由于 App Engine Flexible 应用程序在 Compute Engine 虚拟机上运行,​​因此您可以通过查询元数据服务器来获取默认服务帐户的令牌,如下所示:

> 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】:

    在 Google 的 Node.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 sheet 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
      });
    

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

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

    最好的方法是为所有 Google API 调用设置默认身份验证,然后您就不必将 authClient 传递给任何工作表对象或 API 调用。

    google.options({
      auth: authClient
    });
    

    您仍然可以覆盖工作表(或驱动器或任何其他对象)API 对象或任何 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.
    }
    

    【讨论】:

      猜你喜欢
      • 2020-08-08
      • 1970-01-01
      • 2019-01-23
      • 2019-02-17
      • 2022-01-19
      • 1970-01-01
      • 2020-03-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多