Google Sheets AddOn - 通过服务帐户集成 AppScript 和 BigQuery

Posted

技术标签:

【中文标题】Google Sheets AddOn - 通过服务帐户集成 AppScript 和 BigQuery【英文标题】:Google Sheets AddOn - AppScript & BigQuery Integration via Service Account 【发布时间】:2021-04-10 16:36:55 【问题描述】:

我有一个 Google 表格工作区插件,最近做了一些工作来集成 BigQuery。本质上,BigQuery 保存着每本书的记录,每本书都有作者、标题等,我的插件允许人们将他们读过的书拉到他们的工作表中。工作表中的第一列允许人们从数据库中的所有作者中进行选择,根据该选择,第二列填充来自 BigQuery 的数据以及该作者的所有书籍等。我的插件无需访问用户的 BigQuery,他们只能访问“我的”BgQuery。

这一切都很好,但是当我提交我的插件以供批准时,我被告知

Unfortunately, we cannot approve your request for the use of the following scopes 

https://www.googleapis.com/auth/bigquery

We recommend using service accounts for this type of information exchange. 

这似乎很公平,阅读服务帐户似乎更适合我的用例。我已经完成了创建服务帐户的过程并下载了我的安全详细信息 json 文件,但是我只是不知道如何从 AppScript 实际查询 BigQuery。

在我的非服务帐户方法中,我在 AppScript 中安装了 BigQuery 库并基本上运行

var queryResults = BigQuery.Jobs.query(request, projectId);

我一直在尝试从https://developers.google.com/datastudio/solution/blocks/using-service-accounts 的示例开始工作

function getOauthService() 
var serviceAccountKey = getServiceAccountCreds('SERVICE_ACCOUNT_KEY');// from private_key not private_key_id of JSON file
var serviceAccountEmail = getServiceAccountCreds('SERVICE_ACCOUNT_EMAIL');
return OAuth2.createService('RowLevelSecurity')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(serviceAccountKey)
.setIssuer(serviceAccountEmail)
.setPropertyStore(scriptProperties)
.setCache(CacheService.getScriptCache())
.setScope(['https://www.googleapis.com/auth/bigquery.readonly']);

function getData(request) 
var accessToken = getOauthService().getAccessToken();
var billingProjectId = getServiceAccountCreds('BILLING_PROJECT_ID');
// var email = Session.getEffectiveUser().getEmail();
// return cc
// .newBigQueryConfig()
// .setAccessToken(accessToken)
// .setBillingProjectId(billingProjectId)
// .setUseStandardSql(true)
// .setQuery(BASE_SQL)
// .addQueryParameter('email', bqTypes.STRING, email)
// .build();

上面的代码我已经注释掉了

var cc = DataStudioApp.createCommunityConnector();

在上面的教程中,因为我没有使用 DataStudio,但我真的不确定用什么替换它,所以我可以通过服务帐户使用 AppScript 查询 BigQuery。谁能给点建议?

【问题讨论】:

您应该可以使用您注释掉的代码。服务帐户有自己的电子邮件,因此请尝试使用它。您可以在为您的服务帐号密钥下载的 json 文件中的“client_email”属性下找到您的服务帐号电子邮件。 感谢您的回复。我在 getOauthService 函数var serviceAccountEmail = getServiceAccountCreds('SERVICE_ACCOUNT_EMAIL'); 中提取客户电子邮件。但是我注释掉的代码与从 var cc = DataStudioApp.createCommunityConnector(); 返回的对象有关 - 我没有使用 DataStudioApp 所以我应该使用其他东西吗? 哦。由于您使用的是服务帐户,因此您似乎需要使用 UrlFetchApp 直接利用 BigQuery REST API。 非常感谢,会看看。您有任何指南/示例的链接吗? 【参考方案1】:

根据上面 cmets 中 @TheAddonDepot 的建议,我修改后的代码现在看起来像:

function getBigQueryService() 
  return (
    OAuth2.createService('BigQuery')
      // Set the endpoint URL.
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')

      // Set the private key and issuer.
      .setPrivateKey(JSON_CREDS.private_key) // from the json file downloaded when you create service account
      .setIssuer(JSON_CREDS.client_email). // from the json file downloaded when you create service account

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getScriptProperties())

      // Caching
      .setCache(CacheService.getUserCache())

      // Locking
      .setLock(LockService.getUserLock())

      // Set the scopes.
      .setScope(['https://www.googleapis.com/auth/bigquery.readonly'])
     // .setScope('https://www.googleapis.com/auth/bigquery')
  )



 function queryData()
  const bigQueryService = getBigQueryService()
  if (!bigQueryService.hasAccess()) 
    Logger.log("BQ ERROR IS "+ bigQueryService.getLastError())
  

  //const projectId = bigqueryCredentials.project_id
  var projectId = "<yourprojectid>"

  let url = 'https://bigquery.googleapis.com/bigquery/v2/projects/<yourprojectid>/queries'; //projectID is taken from the security json file for the service account, although it doesn't seem to matter if you use the project code
  
  const headers = 
    Authorization: `Bearer $bigQueryService.getAccessToken()`,
    'Content-Type': 'application/json',
  


 var data = query:"<your query>",useLegacySql:false;
  const options = 
    method: 'post',
    headers,
    //contentType: 'application/json',
    payload: JSON.stringify(data),
   muteHttpExceptions: true // on for debugging
  

  try 
    const response = UrlFetchApp.fetch(url, options)
    const result = JSON.parse(response.getContentText())
    Logger.log("here is result "+ JSON.stringify(result))

   catch (err) 
    console.error(err)
  

【讨论】:

以上是关于Google Sheets AddOn - 通过服务帐户集成 AppScript 和 BigQuery的主要内容,如果未能解决你的问题,请参考以下文章

“未安装以下 SDK 组件:sys-img-x86-addon-google_apis-google-22 和 addon-google_apis-google-22”

使用 Google Sheets API 将图像插入 Google Sheets 单元格

Google word/sheets 常见的使用:

如何将自定义菜单添加到Google Sheet Addon

使用 Sheets API v4 Java 阅读整个 Google 电子表格

使用 Sheets API v4 (Java) 获取 Google 表格上次编辑日期