繁体   English   中英

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

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

目前

我有一个 Google 表格应用脚本“网络应用”

Goolge 表格中的脚本

function doPost(e) {

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

  return "Success!"
}

Google Apps 脚本 Web 应用配置:

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

Who has access: Anyone within MyOrganisation

我想从 AWS Lambda 向上述 Web 应用程序发出 POST 请求。

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 服务帐号

  • 我有一个 GCP 服务帐户,有权访问 Google 表格 API,并且可以不受限制地访问。
  • 此服务帐户具有使用doPost(e)脚本对 Google 工作表的EDIT访问权限。

令牌 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
  }
}

问题

目前的回应:

response:"401"

  • 我找不到任何关于如何设置标头以对我的组织受限 web 应用程序的请求(来自我的服务帐户)进行身份验证的 Google 文档。
  • 当 Web 应用程序对“任何人”开放时,它运行良好,但是一旦我限制为MyOrganisation ,我就很难找到一种方法来验证我的 POST 请求。

帮助!

如何设置对我的 Google 表格 web 应用程序的 POST 请求,以便可以通过身份验证对其进行保护? 现在,我很高兴找到任何方法来验证这个请求(不一定是服务帐户),而不是让它完成对公众开放。

我应该使用这个黑客吗?

我的一个想法是将“秘密”放入我的 lambda function 中,然后公开 web 应用程序。 web 应用程序将检查密钥,如果匹配,将执行 function。

修改点:

  • 为了使用带有脚本的访问令牌访问 Web 应用程序,需要包含 Drive API 的范围。 这些是https://www.googleapis.com/auth/drive.readonlyhttps://www.googleapis.com/auth/drive等等。 参考

  • 当我看到您的显示脚本时,似乎使用google-spreadsheet检索了访问令牌。 当我看到google-spreadsheet的脚本时,似乎这只使用了https://www.googleapis.com/auth/spreadsheets的 scope 。 参考

从这种情况来看,我认为您当前问题的原因可能是由于此。 如果我的理解是正确的,那么下面的修改呢? 在此修改中,访问令牌由 googleapis 从服务帐户中检索到 Node.js。 参考

修改后的脚本:

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

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));
});
  • 运行此脚本时,当 Web Apps 正确部署后,Web Apps 的脚本运行Success! 被退回。

笔记:

  • 如果此修改后的脚本对您的 Web 应用程序设置没有用,请进行如下测试。

    • 请确认您的服务帐户是否可以再次访问电子表格。
    • 请在电子表格上分享服务帐户的 email 地址。 从您展示的 Google Apps 脚本来看,我认为您的 Google Apps 脚本是电子表格的容器绑定脚本。
    • 请将最新脚本反映到 Web 应用程序中。
  • 当您设置服务帐户的private_key时,请包含\n

参考:

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM