【问题标题】:How to authenticate programmatically when running an Apps Script Web App from another Apps Script project从另一个 Apps Script 项目运行 Apps Script Web App 时如何以编程方式进行身份验证
【发布时间】:2023-03-27 20:49:01
【问题描述】:

我是 Apps 脚本的新手,并试图了解在一个帐户中使用另一个帐户运行/触发脚本的基础知识。需要注意的是:我想在用户访问脚本而不是拥有脚本的用户的情况下运行脚本——以便将运行时间分配给访问的用户。

然而,我遇到了以下问题。


从共享设置为任何人都可以编辑的测试电子表格开始,并且脚本项目页面中的以下代码:

function doPost(e){
  var sheet = SpreadsheetApp.openById('1tWV6ELJEGkWkSXvdf9kQemvH-tDVTx0od4JHht2ZBeU');
  var tab = sheet.getSheetByName('ref');
  tab.getRange(1,1).setValue(new Date());
  return ContentService.createTextOutput(0)
}

function doGet(e){
  return doPost(e)
}

并已将项目发布为 Web 应用程序,执行设置为用户访问权限,并为任何人启用访问权限。在浏览器中手动输入以下链接会按照预期将当前时间和页面显示为“0”的单元格 A1 填充,

https://script.google.com/macros/s/AKfycbwNhYg1BRKi38pNf_z0peGuYt6gsqvauCvo-eiGgCYJJk4QDpjm/exec

如果我输入链接时仍然使用创建测试电子表格的帐户登录。

如果我在没有 GSuite 登录的情况下使用其他浏览器输入链接,我需要登录,这也是预期的。毕竟,每次部署 Web 应用程序都需要一个 G Suite 帐户来运行脚本。

但是,当我尝试使用不同的 GSuite 帐户和 Apps 脚本项目触发脚本时,我仍然遇到了登录页面和其他问题。出

function test1(){
  const scriptURL='https://script.google.com/macros/s/AKfycbwNhYg1BRKi38pNf_z0peGuYt6gsqvauCvo-eiGgCYJJk4QDpjm/exec';  
  var response = UrlFetchApp.fetch(scriptURL)
  Logger.log(response.getContentText())
}

function test2(){
  const scriptURL='https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/exec';  
  var response = UrlFetchApp.fetch(scriptURL, {
    method:'POST',
    payload:'nothing'
  });  
  Logger.log(response.getContentText())
}

function test3() {
  var sheet = SpreadsheetApp.openById('AKfycbwNhYg1BRKi38pNf_z0peGuYt6gsqvauCvo-eiGgCYJJk4QDpjm');
  Logger.log(sheet.getName());
}

function test4() {
  var token = ScriptApp.getOAuthToken();
  const scriptURL='https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/exec';  
  var response = UrlFetchApp.fetch(scriptURL, {
    headers: {Authorization:'Bearer '+ token},
    method:'GET',
    payload:'nothing'
  });  
  Logger.log(response.getContentText())
}

test1() 在 Log 中生成一长段文本,以

开头
Logging output too large. Truncating output. 
<!DOCTYPE html>
<html lang="en">
  <head>
  <meta charset="utf-8">
  <meta content="width=300, initial-scale=1" name="viewport">
  <meta name="google-site-verification" content="LrdTUW9psUAMbh4Ia074-BPEVmcpBxF6Gwf0MSgQXZs">
  <title>Sign in - Google Accounts</title>
  <style>

test2() 返回一个错误

Exception: Request failed for https://script.google.com returned code 401. Truncated server response: <!DOCTYPE html><html lang="en"><head><meta name="description" content="Web word processing, presentations and spreadsheets"><meta name="viewport" c... (use muteHttpExceptions option to examine full response)
    at test2(Code:23:30)

由于单元格 A1 未更新,因此两个测试均未触发 doPost(e) 中的脚本。

test1() 好像遇到了登录页面。然而,与此同时,test1() 是通过登录 G Suite 帐户执行的。

还可能值得注意的是,test3() 能够访问相关的 Google 电子表格文件。我也试过打电话给ScriptApp.getOAuthToken(),因为为什么不呢。 test4()test1() 具有相同的响应。

我不知道从哪里开始诊断test2() 中遇到的错误。


如何绕过登录页面?

特别是,有没有办法让任何其他具有相关 Google 电子表格的访问权限的 GSuite 帐户可以访问该脚本,并由访问该电子表格的用户而不是拥有该电子表格的用户执行?

我在使用 POST 版本时做错了什么?

感谢任何帮助!

【问题讨论】:

  • 要解决test2() 问题,如果您使用muteHttpExceptions,您可以从回复中获得更多信息
  • 而且,我相信如果您在此处阅读答案:stackoverflow.com/q/64130847/4243927,您将知道如何在目标 Web 应用程序上授权调用方 Web 应用程序。如果有帮助,请告诉我。
  • @Aerials:感谢您回答我的问题!我确实尝试在链接的问题中以相同的方式添加身份验证令牌,但 headers: {Authorization:'Bearer '+ token} 除外,我得到了相同的响应。
  • 尝试只使用 doGet() 而不是 doPost();

标签: google-apps-script google-sheets web-applications


【解决方案1】:

根据你的问题,我理解你的情况如下。

  • Web Apps的脚本放到1tWV6ELJEGkWkSXvdf9kQemvH-tDVTx0od4JHht2ZBeU的Spreadsheet的容器​​绑定脚本中。
  • 电子表格以Anyone with the linkeditor 共享。
  • Web 应用部署为 Execute the app as: User accessing the web appsWho has access to the app: Anyone

这个答案假设我的上述理解。所以当我的理解不正确时,请告诉我。

修改点:

  • UrlFetchApp,使用payload:'nothing' 时,即使使用method:'GET',也会以POST 方法请求。请注意这一点。
  • 在您的 Web 应用程序脚本中使用https://www.googleapis.com/auth/spreadsheets 的范围。在这种情况下,首先需要通过自己的浏览器(每个用户的浏览器)对范围进行授权。如果不这样做,即使客户端范围的脚本和访问令牌正确,也会出现Authorization needed 的错误。请注意这一点。这似乎是当前的规范。
  • 如果您客户端的整个脚本(test1test4)是您问题中的脚本,则范围是https://www.googleapis.com/auth/script.external_requesthttps://www.googleapis.com/auth/spreadsheets。我认为范围不足以请求 Web 应用程序。在这种情况下,例如,请将// DriveApp.getFiles() 添加到脚本编辑器中。这样,https://www.googleapis.com/auth/drive.readonly 的范围由脚本编辑器自动添加,并且此范围可用于向 Web 应用程序请求。此外,您可以使用https://www.googleapis.com/auth/drive 的范围。
    • 对于https://www.googleapis.com/auth/script.external_requesthttps://www.googleapis.com/auth/spreadsheets的范围,会出现Unauthorized的错误。

当以上几点反映到你的情况时,它变成如下。

用法:

1。准备 Web 应用程序端。 (服务器端)

在这种情况下,我认为可以使用您的设置。请重新部署 Web 应用程序作为新版本以防万一。请再次确认 Web Apps 的 URL。

2。准备客户端。

  1. 请使用自己的浏览器(用户端)访问https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/exec。并请授权Web Apps的范围。

  2. 我想建议修改你的脚本的test4()如下。

     function test4() {
       var token = ScriptApp.getOAuthToken();
       const scriptURL='https://script.google.com/macros/s/AKfycbxay75fTBt3doTyMFUPK0-GpK9hMZ4hVkYdiwYUBMhPfEN6hUJH/exec';  
       var response = UrlFetchApp.fetch(scriptURL, {
         headers: {Authorization:'Bearer '+ token},
         method: 'GET',
     //    payload:'nothing',
         muteHttpExceptions: true
       });  
       Logger.log(response.getContentText())
    
       // DriveApp.getFiles()  // This is used for adding a scope of https://www.googleapis.com/auth/drive.readonly. This is used for requesting to Web Apps.
     }
    
  3. 请运行test4()。这样,0 从 Web Apps 中返回,您可以在日志中看到它。

参考资料:

【讨论】:

  • 非常感谢您的报道!我手动登录并授予权限。在同一个浏览器中,我进行了修改并运行test4(),但在日志中返回错误401:&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Unauthorized&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY BGCOLOR="#FFFFFF" TEXT="#000000"&gt;&lt;H1&gt;Unauthorized&lt;/H1&gt;&lt;H2&gt;Error 401&lt;/H2&gt;&lt;/BODY&gt;&lt;/HTML&gt;。知道接下来我能做什么吗?
  • @Argyll 感谢您的回复。我带来的不便表示歉意。不幸的是,现在当我再次测试我上面的答案的test4 时,没有发生错误并返回0。我可以确认该脚本再次起作用。所以我无法复制你的情况。这是因为我的技术不好。我对此深表歉意。但我愿意支持你。因此,为了正确了解您当前的情况,您能否提供整个脚本和复制问题的详细流程?借此,我想确认一下。如果您能合作解决您的问题,我很高兴。
  • @Argyll 顺便说一句,有一点很重要。这是向 Web 应用程序请求的范围。当客户端的范围不够时,会出现Unauthorized的错误,正如我在回答中已经提到的。所以请注意这一点。关于这个,能否再次确认一下注释行的// DriveApp.getFiles()是否包含在客户端的脚本中?
  • 我很抱歉。我不明白// DriveApp.getFiles() 应该做什么。我添加了该行,这提示了第二次授权。之后,函数按预期运行。非常感谢!
  • @Argyll 感谢您再次回复和测试。我很高兴你的问题得到了解决。作为设置范围的其他方法,还有编辑清单文件的方法(appsscript.json)。但是,在这种情况下,当在脚本中使用使用其他作用域的新方法时,会发生错误,因为作用域是由清单文件固定的。所以在开发脚本时,在我的回答中,我建议使用脚本编辑器自动检测范围。
猜你喜欢
  • 2014-07-08
  • 2016-10-07
  • 2020-02-23
  • 1970-01-01
  • 1970-01-01
  • 2019-07-21
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
相关资源
最近更新 更多