Google Web 应用程序 - 获取用户电子邮件,但 运行 脚本作为所有者

Google Web Apps - Get user email but run scripts as owner

我最近被 google 网络应用所吸引,但我有点进退两难。我正在尝试构建一个对非常特定的用户开放的应用程序,并且他们正在查看的数据会根据他们的访问组进行过滤。

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

问题

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

var email = Session.getActiveUser().getEmail();

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

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";
  }
}

因为用户无权访问我的 google sheet,他们在函数 运行s 时收到错误消息。而且我无法像我一样将 Web 应用程序部署到 运行,因为我需要用户的电子邮件。这个我很明白。

我读过的内容:

关于访问令牌和凭据以及 urlFetchApps 的大量其他帖子和文章......我一点都不明白,老实说,我不知道哪一个更适合我的情况。

我试过的:

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


我意识到我可以将这些参数放在一个单独的 sheet 中并给它们仅查看访问权限,脚本将 运行 正常,但我是额外的,我想做对.

实际上,我将有一些其他功能需要像我一样 运行。如果你处在我的位置,你会从哪里开始?或者有人可以通俗地解释一下吗?我应该研究 之类的东西吗?感谢您的帮助!

总结

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

客户端(主要网络应用程序)将通过 UrlFetchApp 向中间件(负责查询 SpreadSheet 的网络应用程序)发出请求,中间件将进行所需的查询并 return 他们给客户。最后,根据获得的响应,将呈现一个内容或另一个内容。

最小示例

配置项目

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

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

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

在中间件上像这样:

  "oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets"
  ],
  "webapp": {
    "executeAs": "USER_DEPLOYING",
    "access": "ANYONE_ANONYMOUS"
  }

如果您对编辑或查看 appscript.json 有任何疑问,请查看 Manifest and Scopes 文档。

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

代码示例

对于client,我们只需要通过Session.getActiveUser().getEmail()获取正在访问的用户的email,然后发送给中间件就可以得到response。根据获得的响应,我们将呈现一个或另一个内容(我假设存在两个角色: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>" )
}

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

中间件
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
  }))
};

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

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