带有工作表插件的 Google Apps 脚本 PERMISSION_DENIED

Chr*_*ian 5 permissions web-applications google-sheets multiple-accounts google-apps-script

我试图实现一个简单的“多选择器侧边栏”扩展基于我在这个谷歌支持线程中找到的这张

当我复制工作表时,它工作正常,但是当我尝试在我的真实工作表中放入完全相同的代码时,它不再起作用。当我尝试从模板中访问 GA 函数时,它会引发错误。

我创建了一个简化的测试项目,它也无法为我工作。

要重现错误:

  1. https://docs.google.com/spreadsheets/创建一个新的电子表格
  2. 创建第二个工作表(选项卡左下角)并将其命名为 CATEGORIES
  3. 在第一列中填写几个字段。内容无所谓 类别
  4. 进入工具 -> 脚本编辑器

在“code.gs”中输入

function doGet() {
  var html = HtmlService.createHtmlOutputFromFile('Index')
      .setTitle('Multiple selector')
      .setWidth(300);
  SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .showSidebar(html);
}

function onOpen(e) {
    SpreadsheetApp.getUi().createMenu('Index')
        .addItem('Show Sidebar', 'doGet')
        .addToUi();
        doGet();
}

function getOptions() {
  var validation = {
    sheet: 'CATEGORIES',
    range: 'A2:A'
}

  Logger.log("running getOptions");
  Logger.log(SpreadsheetApp.getActive().getSheetByName(validation.sheet).getRange(validation.range).getDisplayValues());
    return SpreadsheetApp.getActive().getSheetByName(validation.sheet).getRange(validation.range).getDisplayValues()
        .filter(String)
        .reduce(function(a, b) {
            return a.concat(b)
        })
}
Run Code Online (Sandbox Code Playgroud)

并创建一个名为 Index.html 的第二个文件(HTML 文件)

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function onFailure(error) {
        var div = document.getElementById('output');
        div.innerHTML = "ERROR: " + error.message;
      }

      google.script.run.withFailureHandler(onFailure)
          .getOptions();
    </script>
  </head>
  <body>
    <div id="output"></div>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

带有代码的测试项目

  1. 保存项目
  2. 单击运行-> 运行函数->“onOpen”(在第一次运行时,您可能需要授权应用程序)

现在在工作表中应该有一个侧边栏,它会为我打开一个错误 PERMISSION_DENIED

在此处输入图片说明

即使我在资源 -> 云平台项目中选择了一个项目,它也不起作用。

奇怪的是,如果我使用原始链接(工作)电子表格并更改代码中的某些内容,它将不再适用于我。

我现在知道的事情: - 它不适用于我的 gmail 或 google 应用程序帐户 - 对于使用相同文档的其他人它有效 - 如果我禁用 Adblocker 仍然不起作用 - 如果我从隐身模式 - 如果我使用 Firefox 而不是 Chrome,它确实有效

来自浏览器的控制台日志

我错过了什么?

小智 9

我遇到过同样的问题。问题确实是由两个或多个 Google 帐户登录到一个会话引起的。

问题是前端由登录用户 X 加载并执行,后端(Code.gs 文件)由登录用户 Y 执行。

因此,解决此问题的方法是检查执行后端代码的用户是否与查看前端代码的用户是同一用户。(在这种情况下:前端是你的侧边栏)

我发现此解决方法适用于我的一个附加组件:

将此函数添加到您的Code.gs文件中。它将检查“前端用户”(initiator),即查看 html 侧边栏”是否与“后端用户”( )相同userEmailAddress。如果不是同一用户,则会抛出错误。如果是同一用户,不会引发错误。

function checkMultipleAccountIssue(initiator) {

var userEmailAddress = Session.getEffectiveUser().getEmail();
if (initiator) {
// check if effective user matches the initiator (the account who triggered the display of the UI)
// Due to a Google bug, if user is connected with multiple accounts inside the same browser session
// google.script.run can be executed by another account than the initiator

 if (initiator != userEmailAddress) {
   console.error({
    message: "Client side calls initiated from wrong account",
    initiator:initiator, // user in frontend (sidebar)
    effectiveUser: userEmailAddress // user in backend (code.gs)
   });
 
 var errorMessage = "You are logged in with multiple accounts.<br>";
     errorMessage+= "This causes errors. Log out with account " + 
                   userEmailAddress;
     errorMessage+= " if you want to continue with the account: " +
     initiator;
 throw new Error(errorMessage);
 }
 else{
   return 'No conflicts found. Good to go.'
  }  
 }
}
Run Code Online (Sandbox Code Playgroud)

在前端(html 侧边栏)中添加加载侧边栏时运行的这段 javascript:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>

var initiator = '<?!= Session.getEffectiveUser().getEmail() ?>'
        console.log('FRONTEND USER: ' + initiator)    
          google.script.run.
            withFailureHandler(function(error){
              alert(error); 
    // or prompt the user to logout! 
    //(HINT: let them click this link: https://google.com/accounts/Logout and login with the correct user.)
            })
            .withSuccessHandler(function(ret){
              console.log(ret)
            })
            .checkMultipleAccountIssue(initiator)



      function onFailure(error) {
        var div = document.getElementById('output');
        div.innerHTML = "ERROR: " + error.message;
      }

      google.script.run.withFailureHandler(onFailure)
          .getOptions();
    </script>
  </head>
  <body>
    <div id="output"></div>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

那个部分

var initiator = '<?!= Session.getEffectiveUser().getEmail() ?>'
Run Code Online (Sandbox Code Playgroud)

是一个应用程序脚本 scriptlet,在 HTML 发送给最终用户之前准备好时,它会被“注入”。如果您想使用此类 scriptlet,则需要将 HTML 侧边栏作为模板加载。要将 HTML 侧边栏加载为模板化 HTML,请更改 doGet() 函数,如下所示:

function doGet() {
  var html = HtmlService.createTemplateFromFile('Index').evaluate()
      
      .setTitle('Multiple selector')
      .setWidth(300);
       
   SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .showSidebar(html);
}
Run Code Online (Sandbox Code Playgroud)

有关 scriptlet 和模板化 HTML 的更多信息,请访问: https: //developers.google.com/apps-script/guides/html/templates#code.gs

这是我找到解决方法的地方:https://sites.google.com/site/scriptsexamples/home/announcements/multiple-accounts-issue-with-google-apps-script

您可以在这里给这个问题加注星标https://issuetracker.google.com/issues/69270374?pli=1以便“更快”地解决它。:)


Fly*_*ars 7

我对“权限被拒绝”错误消息有同样的问题,我发现了这个

https://github.com/burnnat/page-sizer/issues/3

我认为问题在于我在处理此问题时登录了多个 google 帐户。我退出了所有谷歌账户,然后只登录了我试图使用 formMule的一个账户并且它工作正常。

所以我在 chrome 中使用隐身模式尝试了完全相同的代码,只登录了一个帐户,并且有效!

我希望这可以帮助您解决您的问题。

  • 谢谢!这确实为我解决了这个问题 (2认同)