从另一个 Apps Script 项目运行 Apps Script Web App 时如何以编程方式进行身份验证

Arg*_*yll 2 web-applications google-sheets google-apps-script

我是 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)
}
Run Code Online (Sandbox Code Playgroud)

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

https://script.google.com/macros/s/AKfycbwNhYg1BRKi38pNf_z0peGuYt6gsqvauCvo-eiGgCYJJk4QDpjm/exec
Run Code Online (Sandbox Code Playgroud)

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

如果我在未登录 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())
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

doPost(e)由于单元格 A1 未更新,因此这两个测试都没有触发脚本。

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

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

我不知道从哪里开始诊断test2().


如何绕过登录页面?

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

我在 POST 版本中做错了什么?

任何帮助表示赞赏!

Tan*_*ike 5

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

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

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

改装要点:

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

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

用法:

1. 准备 Web Apps 端。(服务器端)

在这种情况下,我认为可以使用您的设置。以防万一,请将 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.
     }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 请跑test4()。这样,0从 Web Apps 返回,您可以在日志中看到它。

参考:

  • @Argyll 感谢您的回复并再次测试。我很高兴您的问题得到了解决。作为设置范围的其他方法,还有编辑清单文件(`appsscript.json`)的方法。但是,在这种情况下,当脚本中使用使用其他作用域的新方法时,会发生错误,因为作用域是由清单文件固定的。因此,在开发脚本时,在我的回答中,我建议使用脚本编辑器自动检测范围。 (2认同)