简体   繁体   English

从 AWS Lambda 将数据发布到 Google Sheet web 应用程序

[英]POST data to Google Sheet web app from AWS Lambda

CURRENTLY目前

I have a Google Sheets App Script 'web app'我有一个 Google 表格应用脚本“网络应用”

Script in Goolge Sheets Goolge 表格中的脚本

function doPost(e) {

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("Sheet1");
  sheet.getRange("A1").setValue("Hello!")

  return "Success!"
}

Google Apps Script Web App Config: Google Apps 脚本 Web 应用配置:

Execute as: Me // or as User. I've tried both.

Who has access: Anyone within MyOrganisation

I want to make a POST request to the above Web App from AWS Lambda.我想从 AWS Lambda 向上述 Web 应用程序发出 POST 请求。

AWS Lambda.js: AWS Lambda.js:

const { GoogleSpreadsheet } = require("google-spreadsheet");

const doc = new GoogleSpreadsheet(
    {spreadsheetId}
);
 
await doc.useServiceAccountAuth({
    client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
    private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, "\n"),
});

let token = doc["jwtClient"]["credentials"]["access_token"];

await new Promise((resolve, reject) => {
    
    const options = {
      host: 'script.google.com',
      path: "/macros/s/{myscriptid}/exec",  //<-- my web app path!
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': "Bearer "+ token
      }
    };
    
    //create the request object with the callback with the result
    const req = HTTPS.request(options, (res) => {
      resolve(JSON.stringify(res.statusCode));
    });

    // handle the possible errors
    req.on('error', (e) => {
      reject(e.message);
    });
    
    //do the request
    req.write(JSON.stringify(data));

    //finish the request
    req.end();
  });

console.log("response:"+JSON.stringify(response))

GCP Service Account GCP 服务帐号

  • I have a GCP Service Account, with permission to Google Sheets API, and otherwise unrestricted access.我有一个 GCP 服务帐户,有权访问 Google 表格 API,并且可以不受限制地访问。
  • This Service account has EDIT access to the Google Sheet with the doPost(e) script.此服务帐户具有使用doPost(e)脚本对 Google 工作表的EDIT访问权限。

Token Output:令牌 Output:

"jwtClient": {
  "_events": {},
  "_eventsCount": 0,
  "transporter": {},
  "credentials": {
      "access_token": "somelongvalue...............", //<-- what I use
      "token_type": "Bearer",
      "expiry_date": 1661662492000,
      "refresh_token": "jwt-placeholder"
  },
  "certificateCache": {},
  "certificateExpiry": null,
  "certificateCacheFormat": "PEM",
  "refreshTokenPromises": {},
  "eagerRefreshThresholdMillis": 300000,
  "forceRefreshOnFailure": false,
  "email": "serviceaccount@appspot.gserviceaccount.com",
  "key": "-----BEGIN PRIVATE KEY-----\nsomelongvalue=\n-----END PRIVATE KEY-----\n",
  "scopes": [
      "https://www.googleapis.com/auth/spreadsheets"
  ],
  "subject": null,
  "gtoken": {
      "key": "-----BEGIN PRIVATE KEY-----\nsomelongvalue=\n-----END PRIVATE KEY-----\n",
      "rawToken": {
          "access_token": "somelongvalue...............",
          "expires_in": 3599,
          "token_type": "Bearer"
      },
      "iss": "serviceaccount@appspot.gserviceaccount.com",
      "sub": null,
      "scope": "https://www.googleapis.com/auth/spreadsheets",
      "expiresAt": 1661662492000
  }
}

ISSUE问题

Current response:目前的回应:

response:"401"

  • I cannot find any Google documentation on how to setup the headers to authenticate a request (from my service account) to my organisation restricted web app.我找不到任何关于如何设置标头以对我的组织受限 web 应用程序的请求(来自我的服务帐户)进行身份验证的 Google 文档。
  • When the Web App is open to "Anyone" then it runs fine, but as soon as I restrict to MyOrganisation , I struggle to find a way to authenticate my POST request.当 Web 应用程序对“任何人”开放时,它运行良好,但是一旦我限制为MyOrganisation ,我就很难找到一种方法来验证我的 POST 请求。

HELP!帮助!

How do I set up a POST request to my Google Sheets web app such that it can be protected by authentication?如何设置对我的 Google 表格 web 应用程序的 POST 请求,以便可以通过身份验证对其进行保护? Right now, I'd be happy to find ANY means to authenticate this request (not necessarily a service account) that doesn't leave it completed open to public.现在,我很高兴找到任何方法来验证这个请求(不一定是服务帐户),而不是让它完成对公众开放。

Should I use this hack?我应该使用这个黑客吗?

One idea I had was to put a "secret" into my lambda function, and then make the web app public.我的一个想法是将“秘密”放入我的 lambda function 中,然后公开 web 应用程序。 The web app would check the secret, if if matched, would execute the function. web 应用程序将检查密钥,如果匹配,将执行 function。

Modification points:修改点:

  • In order to access Web Apps using the access token with a script, the scopes of Drive API are required to be included.为了使用带有脚本的访问令牌访问 Web 应用程序,需要包含 Drive API 的范围。 Those are https://www.googleapis.com/auth/drive.readonly , https://www.googleapis.com/auth/drive , and so on.这些是https://www.googleapis.com/auth/drive.readonlyhttps://www.googleapis.com/auth/drive等等。 Ref 参考

  • When I saw your showing script, it seems that the access token is retrieved using google-spreadsheet .当我看到您的显示脚本时,似乎使用google-spreadsheet检索了访问令牌。 When I saw the script of google-spreadsheet , it seems that this uses only the scope of https://www.googleapis.com/auth/spreadsheets .当我看到google-spreadsheet的脚本时,似乎这只使用了https://www.googleapis.com/auth/spreadsheets的 scope 。 Ref 参考

From this situation, I thought that the reason for your current issue might be due to this.从这种情况来看,我认为您当前问题的原因可能是由于此。 If my understanding is correct, how about the following modification?如果我的理解是正确的,那么下面的修改呢? In this modification, the access token is retrieved by googleapis for Node.js from the service account.在此修改中,访问令牌由 googleapis 从服务帐户中检索到 Node.js。 Ref参考

Modified script:修改后的脚本:

Google Apps Script side: Google Apps 脚本方面:

function doPost(e) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("Sheet1");
  sheet.getRange("A1").setValue("Hello!")
  return ContentService.createTextOutput("Success!"); // Modified
}

Node.js side: Node.js侧:

const { google } = require("googleapis");
const HTTPS = require("https");

const auth = new google.auth.JWT(
  "###", // Please set client_email here.
  null,
  "###", // Please set private_key here. When you set private_key of service account, please include \n.
  ["https://www.googleapis.com/auth/drive.readonly"],
  null
);

function req(token) {
  return new Promise((resolve, reject) => {

    const data = { key1: "value1" }; // Please set your value.

    const options = {
      host: "script.google.com",
      path: "/macros/s/{myscriptid}/exec",  //<-- my web app path!
      method: "POST",
      headers: {Authorization: "Bearer " + token},
    };
    const req = HTTPS.request(options, (res) => {
      if (res.statusCode == 302) {
        HTTPS.get(res.headers.location, (res) => {
          if (res.statusCode == 200) {
            res.setEncoding("utf8");
            res.on("data", (r) => resolve(r));
          }
        });
      } else {
        res.setEncoding("utf8");
        res.on("data", (r) => resolve(r));
      }
    });
    req.on("error", (e) => reject(e.message));
    req.write(JSON.stringify(data));
    req.end();
  });
}

auth.getAccessToken().then(({ token }) => {
  req(token).then((e) => console.log(e)).catch((e) => console.log(e));
});
  • When this script is run, when the Web Apps is correctly deployed, the script of Web Apps is run and Success!运行此脚本时,当 Web Apps 正确部署后,Web Apps 的脚本运行Success! is returned.被退回。

Note:笔记:

  • If this modified script was not useful for your Web Apps setting, please test as follows.如果此修改后的脚本对您的 Web 应用程序设置没有用,请进行如下测试。

    • Please confirm whether your service account can access to the Spreadsheet again.请确认您的服务帐户是否可以再次访问电子表格。
    • Please share the email address of the service account on the Spreadsheet.请在电子表格上分享服务帐户的 email 地址。 From your showing Google Apps Script, I thought that your Google Apps Script is the container-bound script of the Spreadsheet.从您展示的 Google Apps 脚本来看,我认为您的 Google Apps 脚本是电子表格的容器绑定脚本。
    • Please reflect the latest script to the Web Apps.请将最新脚本反映到 Web 应用程序中。
  • When you set private_key of service account, please include \n .当您设置服务帐户的private_key时,请包含\n

References:参考:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Firebase | 谷歌表 | 应用脚本 | 如何将列中的数据而不是行中的数据从 Firebase 保存到 Google 表格? - Firebase | Google Sheet | App Script | How do I save the data in column instead of row from Firebase to Google Sheet? 如何从运行 PHP 的 Google App Engine 安全访问 AWS RDS 数据 - How to securely access AWS RDS data from Google App Engine running PHP 如何在使用来自 AWS Lambda 的 307 重定向(POST 方法和正文)在 python 中传递请求正文 - How to do pass a Request Body while doing a 307 Redirect with a( POST Method and body ) from AWS Lambda , in python 从 AWS Lambda 调用中保存数据的最佳方法? - Best method to persist data from an AWS Lambda invocation? 从 DynamoDB 读取数据并将其存储在 AWS Lambda 的变量中 - Read and store data from DynamoDB in variable in AWS Lambda 使用aws lambda将批处理数据从aws sqs存储到aws s3 - store batch data from aws sqs to aws s3 using aws lambda 从在本地系统而非 S3 上运行的 node.js 应用程序调用 AWS Lambda - Invoke AWS Lambda from a node.js app running on local system not S3 AWS Lambda - 无法在 lambda 函数中获取 Cognito 用户数据 - AWS Lambda - Can't get Cognito user data in lambda function 使用参数从 PHP 调用 AWS Lambda - Invoke AWS Lambda from PHP with params 无法从 VPC 中的 Lambda 连接到 AWS Keyspaces - Unable to connect to AWS Keyspaces from a Lambda in a VPC
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM