Google Apps 脚本 PERMISSION_DENIED 带有表格插件

Google Apps Script PERMISSION_DENIED with sheets addon

我尝试基于THIS SHEET which I found in this Google support thread

实现一个简单的"Multi selector sidebar"扩展

当我复制 sheet 时它工作正常,但是当我尝试将完全相同的代码放入我的真实 sheet 时,它不再工作了。 当我尝试从模板中访问 GA 函数时它抛出错误。

我创建了一个简化的测试项目,但对我也不起作用。

重现错误:

  1. https://docs.google.com/spreadsheets/
  2. 创建一个新的点差sheet
  3. 创建第二个 sheet(选项卡左下方)并将其命名为 CATEGORIES
  4. 在第一列中填写几个字段。内容不重要
  5. 转到工具 -> 脚本编辑器

在"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)
        })
}

并创建名为 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>

  1. 保存项目
  2. 点击运行->运行功能->"onOpen"(首先运行您可能需要授权该应用程序)

现在 sheet 中应该有一个侧边栏,它打开时出现错误 PERMISSION_DENIED

即使我 select 在 Resources -> Cloud platform project 中的项目它也不会工作。

奇怪的是,如果我使用原始链接(工作)传播sheet 并更改代码中的某些内容,它对我来说将不再有效。

我现在知道的事情: - 它不适用于我的 Gmail 或 google 应用程序帐户 - 对于使用相同文档的其他人,它可以工作 - 如果我禁用 Adblocker 仍然不起作用 - 如果我从隐身模式访问 sheet 则不起作用 - 如果我使用 Firefox 而不是 Chrome

,它确实有效

我错过了什么?

我对 "permission denied" 错误消息有同样的问题,我发现了这个

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

I think the issue is that I'm logged into multiple google accounts when I am working on this. I logged out of all google accounts, then only logged into the one account that I was trying to use formMule and it worked.

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

希望对您的问题有所帮助。

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

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

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

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

将此函数添加到您的 Code.gs 文件中。它将检查正在查看 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.'
  }  
 }
}

在前端(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>

部分

var initiator = '<?!= Session.getEffectiveUser().getEmail() ?>'

是一个应用程序脚本 scriptlet,当 HTML 在发送给最终用户之前准备好时,它会被“注入”。如果你想使用这样的小脚本,你需要加载你的 HTML-sidebar 作为模板。 要将 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);
}

有关小脚本和模板化的更多信息 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 以便“更快”地解决它。 :)