Google Web Apps - 获取用户电子邮件但以所有者身份运行脚本

Niy*_*iya 2 google-apps-script google-sheets-api

我最近迷上了谷歌网络应用程序,但我遇到了一些进退两难的问题。我正在尝试构建一个对非常特定的用户开放的应用程序,并且他们正在查看的数据根据​​其访问组进行过滤。

在谷歌表格中,我列出了用户电子邮件及其各自的访问组。A 列 - 电子邮件,B 列 - 访问组

问题

当用户访问网络应用程序时,我使用它来获取他们的电子邮件:

var email = Session.getActiveUser().getEmail();
Run Code Online (Sandbox Code Playgroud)

然后我运行此代码来获取他们的访问组:

function validate(email){
  var sheet = SpreadsheetApp.openById(ID).getSheetByName(ssUserList);
  try{
    var group = getRowsData(sheet).find(e => e.userEmail === email).securityGroup;
    return group;
  } catch(e){
    return "Not Authorized";
  }
}
Run Code Online (Sandbox Code Playgroud)

由于用户无权访问我的谷歌工作表,因此在函数运行时他们会收到错误。而且我无法部署 Web 应用程序以我的身份运行,因为我需要用户的电子邮件。我很明白这一点。

我读过的内容:

关于访问令牌和凭据以及 urlFetchApps 的大量其他帖子和文章......我不理解其中任何一个,说实话,我不知道哪一个对我的情况更有意义。

我尝试过的:

我无法使用我发现的第一个可用选项,即访问Web 应用程序 1(以用户身份运行),然后使用用户电子邮件作为参数调用 Web 应用程序 2,因为如果他们共享来自 Web 应用程序 2 的链接,则任何人都可以看到这些数据,而我正在处理非常敏感的数据。


我意识到我可以将这些参数放在单独的工作表中,并给予它们仅查看访问权限,并且脚本将运行良好,但我是额外的,我想做得正确。

实际上,我还有一些其他功能需要以我的身份运行。如果你处于我的处境,你会从哪里开始?或者有人可以通俗地解释一下吗?我应该研究这样的事情?任何帮助表示赞赏!

小智 5

概括

正如此处建议的,其中一种可能性是创建一个单独的 Web 应用程序来处理对 SpreadSheets 的访问。

客户端(主 Web 应用程序)将通过UrlFetchApp中间件(负责查询 SpreadSheet 的 Web 应用程序)发出请求,中间件将进行所需的查询并将其返回给客户端。最后,根据获得的响应,将呈现一种或另一种内容。

最小的例子

配置项目

首先,我们创建两个 GAS 项目,一个称为 Main,另一个称为中间件。要点是中间件将作为 运行,USER_DEPLOYING客户端将作为 运行USER_ACCESSING。这允许访问工作表而不需要额外的权限。

appscripts.json文件在客户端上看起来像这样。:

  "oauthScopes": [
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/userinfo.email"
  ],  
  "webapp": {
    "executeAs": "USER_ACCESSING",
    "access": "ANYONE"
  }

Run Code Online (Sandbox Code Playgroud)

在中间件上就像这样:

  "oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets"
  ],
  "webapp": {
    "executeAs": "USER_DEPLOYING",
    "access": "ANYONE_ANONYMOUS"
  }
Run Code Online (Sandbox Code Playgroud)

如果您对编辑或查看有任何疑问appscript.json,请查看清单范围文档。

注意"access": "ANYONE""access": "ANYONE_ANONYMOUS"仅用于测试目的。这是危险的,应该根据项目的特定需求进行审查。

代码示例

对于客户端来说,我们只需要询问正在访问的用户的电子邮件Session.getActiveUser().getEmail(),然后将其发送给中间件即可获得响应。根据获得的响应,我们将呈现一种或另一种内容(我假设存在两个角色:USERADMIN

客户
const doGet = () => {
  var data = {email: Session.getActiveUser().getEmail()}
  var options = {
    'method': 'POST',
    'contentType': 'application/json',
    'payload': JSON.stringify(data)
  }
  var fetch = UrlFetchApp.fetch(URL_MIDDLEWARE, options)

  var userAccess = JSON.parse(fetch).accessLevel
  return HtmlService.createHtmlOutput(
    userAccess === "ADMIN"
    ? `<h1>${data.email} - ADMIN USER</h1>`
    : userAccess === "USER" 
    ? `<h1>${data.email} - COMMON USER</h1>`
    : "<h1>Unauthorized</h1>" )
}
Run Code Online (Sandbox Code Playgroud)

对于中间件,我们需要获取该电子邮件并将其与我们的工作表进行比较,以检查用户的访问级别。然后我们返回结果。

中间件
const doPost = (request) => {
  // destructuring the request
  const { parameter, postData: { contents, type } = {} } = request;
  const userEmail = JSON.parse(contents).email;
  let userAccess = SpreadsheetApp.openById(SPREADSHEET_ID).getRange('A1:B2').getValues()
  // This can be replaced by a filter function
  let userAccessLevel;
  for (let user of userAccess) { if (userEmail == user[0]) userAccessLevel = user[1] }
  return ContentService.createTextOutput(Utilities.jsonStringify({
    user: userEmail,
    accessLevel: userAccessLevel
  }))
};
Run Code Online (Sandbox Code Playgroud)

最后,您访问主 Web 应用程序以检查一切是否正常。

请记住,这是一个测试实现,不应在生产中使用。如果您需要有关这些主题的更多信息,可以访问以下链接: