编辑器插件授权

许多 Google Apps 脚本应用的授权过程都很简单。当有人尝试使用脚本项目时,该项目会请求所需的任何缺失权限。

编辑器插件的授权模型之所以更复杂,原因有以下几点:

  • 当用户创建文件时,即使尚未授权,用户安装的所有插件也会列在扩展程序菜单中。

  • 这些插件可用于 Google 云端硬盘中可与协作者共享的文件。未安装 Editor 加载项的协作者会在文件创建者使用该加载项的文档中看到它。

  • 编辑器插件会在文档打开时自动运行其 onOpen 函数。

为了保护用户数据,我们应用了授权模式,使 onOpen 无法使用某些服务。本指南将介绍您的代码可以执行哪些操作以及何时可以执行这些操作。

授权模型

编辑器插件的授权模式取决于其状态,而状态取决于使用该插件的用户:安装该插件的用户或协作者。

编辑器插件状态

扩展程序菜单中的编辑器插件已安装、已启用或同时已安装和已启用:

  • 插件在用户或其管理员从 Google Workspace Marketplace 获取插件并授权其访问用户的 Google 数据后,会为特定用户安装
  • 当有人在文档、表单、演示文稿或电子表格中使用某个插件时,该插件就会在相应文件中启用
  • 当用户协作处理文件时,如果其中一人使用某项插件,则该插件会为该用户安装,并为该文件启用

下表总结了“已安装”和“已启用”之间的区别。当您将脚本作为插件进行测试时,可以在任一状态或两种状态下运行测试。

已安装 已启用
适用对象 用户 文档、表单、演示文稿或电子表格
原因 从商店获取加购项 在以下情况下从商店获取插件:使用相应文档、表单、演示文稿或电子表格时,或
在相应文档、表单、演示文稿或电子表格中使用之前安装的插件
菜单的公开范围 仅限该用户在打开或创建的所有文档、表单、演示文稿或电子表格中 相应文档、表单、演示文稿或电子表格的所有协作者
onOpen 的授权模式 AuthMode.NONE
(除非它也处于启用状态,在这种情况下,AuthMode.LIMITED)
AuthMode.LIMITED

授权模式

当用户打开文档、表单、演示文稿或电子表格时,编辑器插件的 onOpen 函数会自动运行。为保护用户的数据,Apps 脚本限制了 onOpen 函数的功能。编辑器插件状态决定了 onOpen 函数的运行授权模式。

如果文件、表单、演示文稿或电子表格中启用了编辑器插件,onOpen 会在 AuthMode.LIMITED 中运行。如果插件未启用,仅处于已安装状态,onOpen 会在 AuthMode.NONE 中运行。

AuthMode.NONE 中,除非用户通过点击或运行自定义函数与插件互动,否则插件无法运行某些服务。如果您的插件尝试在 onOpenonInstall 或全局范围内使用这些服务,权限会失败,并且其他调用(例如填充菜单)会停止。帮助是唯一受支持的选项。

如需运行受限的服务调用,您必须使用 AuthMode.FULL 授权模式。用户互动功能(例如点击菜单选项)仅在此模式下运行。在 AuthMode.FULL 模式下运行代码后,该插件可以使用所有已获授权的范围。

只有已发布的编辑器插件才能位于 AuthMode.NONE 中;未发布的编辑器插件在 AuthMode.LIMITED 中运行 onOpen。不过,无论采用哪种授权模式,为此,请测试编辑器插件

Apps 脚本会将授权模式作为 Apps 脚本事件参数 authMode 的属性传递;ee.authMode 的值对应于 Apps 脚本 ScriptApp.AuthMode 枚举中的常量。

授权模式适用于所有 Apps 脚本执行方法,包括从脚本编辑器、菜单项或 Apps 脚本 google.script.run 调用运行。不过,只有当脚本因 触发器(例如 onOpenonEditonInstall)而运行时,才能检查 e.authMode 属性。Google 表格中的自定义函数使用自己的授权模式 AuthMode.CUSTOM_FUNCTION,该模式与 LIMITED 类似,但限制略有不同。在所有其他情况下,脚本在 AuthMode.FULL 中运行,如下表中所述。

NONE LIMITED CUSTOM_FUNCTION FULL
发生时间 onOpen(如果用户已安装插件,但未在文档、表单、演示文稿或电子表格中启用该插件) onOpen(所有其他时间)
onEdit(仅限在 Google 表格中使用)
自定义函数 所有其他时间,包括:
可安装的触发器
onInstall
google.script.run
用户数据访问权限 仅限语言区域 仅限语言区域 仅限语言区域
对文档、表单、演示文稿或电子表格的访问权限 是 - 只读
访问界面 添加菜单项 添加菜单项
可使用 Properties
有权访问 JdbcUrlFetch
其他服务 Logger
Utilities
不访问用户数据的任何服务 不访问用户数据的任何服务 所有服务

编辑器插件的授权生命周期

当为当前用户安装某个插件或在当前文件中启用某个插件时,打开相应文档、表单、演示文稿或电子表格时,系统会为该文件加载该插件。该插件会列在扩展程序菜单中,并开始监听简单触发器 onInstallonOpenonEdit。如果用户点击扩展程序菜单项,系统会运行该扩展程序。

编辑器插件已安装

从商店安装编辑器插件后,其 onInstall 函数会在 AuthMode.FULL 中运行。在此授权模式下,插件可以运行复杂的设置例程。您还应使用 onInstall 创建菜单项,因为文档、表单、演示文稿或电子表格已打开,但您的 onOpen 函数尚未运行。以下示例展示了如何从 onInstall 函数调用 onOpen 函数:

function onInstall(e) {
  onOpen(e);
  // Perform additional setup as needed.
}

编辑器插件已打开

当文档、表单、演示文稿或电子表格打开时,系统会加载当前用户已安装或任何协作者已在文件中启用的每个编辑器插件,并调用每个插件的 onOpen 函数。onOpen 运行的授权模式取决于加购项是否已安装或启用。

如果插件仅创建基本菜单,则模式无关紧要。以下示例展示了一个基本的 onOpen 函数:

function onOpen(e) {
  SpreadsheetApp.getUi().createAddonMenu() // Or DocumentApp.
      .addItem('Insert chart', 'insertChart')
      .addItem('Update charts', 'updateCharts')
      .addToUi();
}

如需添加基于存储的 Apps 脚本属性的动态菜单项、读取当前文件的内容或执行其他高级任务,您必须确定授权模式并妥善处理。

以下示例展示了一个高级 onOpen 函数,该函数会根据授权模式更改其操作:

function onOpen(e) {
  var menu = SpreadsheetApp.getUi().createAddonMenu(); // Or DocumentApp.
  if (e && e.authMode == ScriptApp.AuthMode.NONE) {
    // Add a normal menu item (works in all authorization modes).
    menu.addItem('Start workflow', 'startWorkflow');
  } else {
    // Add a menu item based on properties (doesn't work in AuthMode.NONE).
    var properties = PropertiesService.getDocumentProperties();
    var workflowStarted = properties.getProperty('workflowStarted');
    if (workflowStarted) {
      menu.addItem('Check workflow status', 'checkWorkflow');
    } else {
      menu.addItem('Start workflow', 'startWorkflow');
    }
  }
  menu.addToUi();
}

onOpen 函数运行时,整个脚本会加载,并且全局语句会以与 onOpen 相同的授权模式运行。如果授权模式禁止使用全局语句,则全局语句和 onOpen 都无法运行。如果已发布的插件无法添加其菜单项,请查看浏览器控制台,看看是否返回了错误。然后,检查您的脚本,看看 onOpen 函数或全局变量是否调用了 AuthMode.NONE 中不允许的服务。

AuthMode.LIMITED 中执行时,插件无法打开边栏或对话框。您可以使用菜单项打开侧边栏和对话框,因为这些菜单项在 AuthMode.FULL 中运行。

用户运行编辑器插件

当用户点击扩展程序菜单项时,Apps 脚本会先检查用户是否已安装该插件,如果未安装,则会提示用户进行安装。如果用户已授权该插件,脚本会运行 AuthMode.FULL 中与相应菜单项对应的函数。如果尚未启用,则在文档、表单、演示文稿或电子表格中启用该插件。

排查插件菜单无法呈现的问题

如果您的代码未正确管理授权模式,则插件菜单可能无法呈现。例如:

  • 某插件尝试运行当前授权模式不支持的 Apps 脚本服务。

  • 插件在用户与其互动之前尝试运行服务调用。

如需移除或重新排列导致 AuthMode.NONE 中出现权限错误的服务调用,请尝试以下操作:

  1. 打开插件的 Apps 脚本项目,然后找到 onOpen 函数。
  2. onOpen 函数中搜索提及 Apps 脚本服务或与其关联的对象(例如 PropertiesServiceSpreadsheetAppGmailApp)的内容。
  3. 如果某项服务用于创建界面元素以外的任何用途,请将其移除或封装在注释块中。仅保留以下方法:.getUi.createMenu.addItem.addToUi。此外,还可查找并移除函数之外的任何服务。
  4. 找出可能包含上一步中注释掉或移除的代码行的函数,尤其是那些使用它们生成的信息的函数,并将服务调用移至需要它们的函数。重新排列或重写代码库,以适应上一步中做出的更改。
  5. 保存代码并创建测试部署。 创建测试部署时,请确保配置字段为为当前用户安装,并且“配置”框下方的文字显示为AuthMode.NONE 中进行测试
  6. 启动测试部署,然后打开扩展程序菜单。
  7. 如果所有菜单项都显示出来,则问题已解决。 如果您只看到帮助菜单,请返回到第 1 步。 您可能错过了服务电话。