如何在 Twilio 无服务器功能中将 googleapis google.auth.GoogleAuth() 用于 google API 服务帐户?

Posted

技术标签:

【中文标题】如何在 Twilio 无服务器功能中将 googleapis google.auth.GoogleAuth() 用于 google API 服务帐户?【英文标题】:How to use googleapis google.auth.GoogleAuth() for google API service account in Twilio serverless function? 【发布时间】:2021-11-01 13:50:55 【问题描述】:

由于没有 FS 路径可作为 keyFile 值提供,

基于此处 (https://www.section.io/engineering-education/google-sheets-api-in-nodejs/) 和此处 (Google api node.js client documentation) 的示例,我的代码基于此处的示例 (Receive an inbound SMS),看起来像...

const google = require('googleapis')
const fs = require('fs')
exports.handler = async function(context, event, callback) 
  const twiml = new Twilio.twiml.MessagingResponse()
  
  // console.log(Runtime.getAssets()["/gservicecreds.private.json"].path)
  console.log('Opening google API creds for examination...')
  const creds = JSON.parse(
    fs.readFileSync(Runtime.getAssets()["/gservicecreds.private.json"].path, "utf8")
  )
  console.log(creds)
  
  // connect to google sheet
  console.log("Getting googleapis connection...")
  const auth = new google.auth.GoogleAuth(
    keyFile: Runtime.getAssets()["/gservicecreds.private.json"].path,
    scopes: "https://www.googleapis.com/auth/spreadsheets",
  )
  const authClientObj = await auth.getClient()
  const sheets = google.sheets(version: 'v4', auth: authClientObj)
  const spreadsheetId = "myspreadsheetID"
  
  console.log("Processing message...")
  if (String(event.Body).trim().toLowerCase() == 'KEYWORD') 
    console.log('DO SOMETHING...')
    try 
      // see https://developers.google.com/sheets/api/guides/values#reading_a_single_range
      let response = await sheets.spreadsheets.values.get(
        spreadsheetId: spreadsheetId,
        range: "'My Sheet'!B2B1000"
      )
      console.log("Got data...")
      console.log(response)
      console.log(response.result)
      console.log(response.result.values)
     catch (error) 
      console.log('An error occurred...')
      console.log(error)
      console.log(error.response)
      console.log(error.errors)
    
   
  
  // Return the TwiML as the second argument to `callback`
  // This will render the response as XML in reply to the webhook request
  return callback(null, twiml)

...其中代码中引用的资产是通过为 Google APIs Service Account 创建密钥对并手动将 JSON 数据复制/粘贴为无服务器函数编辑器 Web UI 中的资产而生成的 JSON。

我看到类似...的错误消息

发生错误...

响应:'[Object]',配置:'[Object]',代码:403,错误:'[Object]'

config: '[Object]', data: '[Object]', headers: '[Object]', status: 403, statusText: 'Forbidden', request: '[Object]'

[ message: '调用者没有权限', domain: 'global', reason: 'forbidden' ]

假设这是由于没有在auth const 声明中正确读取 keyFile(IDK 怎么做,因为我看到的所有示例都假定本地文件路径为值,但 IDK 如何让函数访问该文件以获取无服务器函数(我在代码块中的尝试实际上只是在黑暗中拍摄)。

仅供参考,我可以看到服务帐户在 google API 控制台中具有编辑角色(尽管我注意到“此服务帐户可以访问的资源”有错误

“无法为您有权查看至少一个祖先的政策报告的所选项目的祖先提供资金”

(我真的不知道这意味着什么或暗示什么,对此非常陌生))。例如...

谁能帮忙解决这里可能出了什么问题?

(顺便说一句,如果我在评论中遗漏了一些非常愚蠢/明显的东西(例如错字),只需 LMK 在评论中删除此帖子(因为它不会为其他人提供任何未来价值))

【问题讨论】:

【参考方案1】:

调用者没有权限',域:'global',原因:'forbidden

这实际上意味着当前经过身份验证的用户(服务帐户)无权执行您要求它执行的操作。

您正在尝试访问电子表格。

此表是否在服务帐户 google drive 帐户上?如果没有,您是否与服务帐户共享了工作表?

服务帐户就像任何其他用户一样,如果它无法访问它无法访问的东西。转到 google drive web 应用程序并与服务帐户共享工作表,就像与任何其他用户共享工作表一样,只需使用服务帐户电子邮件地址,我认为它称为客户端 ID,其中包含 @。

委派给您域中的用户

如果您正确设置了委派,那么您可以让服务帐户充当您域中有权访问该文件的用户。

delegated_credentials = credentials.with_subject('userWithAccess@YourDomain.org')

【讨论】:

IC,有趣。不知道。不幸的是,当我尝试与我的 .iam.gserviceaccount.com 电子邮件共享工作表时,我刚刚了解到“无法在 之外共享项目”(我认为这与 G Suite 相关),因此无法测试。无论如何要修复/解决这个问题(或者我应该再发一个帖子)?关于如何将正确的 keyFile 值传递给 google.auth.GoogleAuth() 函数的任何想法(假设赞成票来自其他有类似问题的人)? 如果它的 gsuite 则尝试确保您已将委托添加到服务帐户。服务帐户需要委派给域上的用户。检查更新您只需将 with_subject 代码行添加到授权中。 这行代码应该放在代码中的什么位置(IDK 如何适合google.auth.GoogleAuthauth.getClient 连接步骤)?顺便说一句,刚刚尝试设置委托(developers.google.com/admin-sdk/directory/v1/guides/delegation)并注意到它创建了 OAuth2 凭据。我正在尝试从自动运行的 Twilio 无服务器函数调用 googleapis。在我完成的所有情况下,OAuth2 客户端都需要手动单击同意屏幕。这会是一个问题吗(仍在设置,但尽早知道这一点会很好)? 尝试阅读google-auth.readthedocs.io/en/master/reference/… 或查看github.com/googleapis/google-api-nodejs-client/issues/1699 请注意:其他帖子对我的帮助最大 (***.com/a/61932919/8236733),因此我访问工作表的代码对大多数示例中的内容进行了最小的更改,最终看起来像...@987654329 @(基于此处的链接答案)。

以上是关于如何在 Twilio 无服务器功能中将 googleapis google.auth.GoogleAuth() 用于 google API 服务帐户?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Keras / Tensorflow 中将(无,)批量维度重新引入张量?

Twilio 加入 Google Hangouts 电话会议

带有 Twilio 的 Google App Engine:ImportError:没有名为 pytz 的模块 [重复]

如何在解析服务器上配置 Twilio?

使用 Google App Engine 和 Django 将第三方库 (twilio) 添加到项目中

如何在 Cordova 中将 org.chromium.identity 用于本地 google connect