编辑器插件授权

许多基于 Apps Script 的应用的授权非常简单,因为当用户尝试使用脚本项目时,脚本项目会请求获取缺少的所有权限。

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

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

  • 这些插件适用于可与协作者共享的 Google 云端硬盘文件。未安装编辑器插件的工作协作者在文件创建者使用该插件处理的文档中会看到该插件。

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

为保护用户数据,系统会应用授权模式,使 onOpen() 无法使用某些服务。本指南可帮助您了解代码的用途和使用时机。

授权模型

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

编辑器插件状态

扩展程序菜单中的编辑器插件已安装或已启用。

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

下表总结了“已安装”和“已启用”之间的区别。请注意,以插件形式测试脚本时,您可以在上述任一状态或两种状态下运行测试。

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

授权模式

当用户打开文档、表单、演示文稿或电子表格时,编辑器插件中的 onOpen() 函数会自动运行。为保护用户数据,Apps Script 会限制 onOpen() 函数可以执行的操作。编辑器插件状态决定了 onOpen() 函数在哪种授权模式下运行。

如果文件、表单、演示文稿或电子表格中启用了编辑器插件,onOpen() 将在 AuthMode.LIMITED 中运行。如果插件未启用,而仅安装onOpen() 将在 AuthMode.NONE 中运行。

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

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

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

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

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

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

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

已安装编辑器插件

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

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

打开编辑器插件

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

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

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

如需根据存储的 Apps Script 属性添加动态菜单项、读取当前文件的内容或执行其他高级任务,您必须识别授权模式并进行适当处理。

以下示例展示了一个高级 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();
}

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

用户运行编辑器插件

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

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

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

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

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

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

  1. 打开您的插件对应的 Apps 脚本项目,然后找到 onOpen() 函数。
  2. onOpen() 函数中搜索提及 Apps Script 服务或与之关联的对象(例如 PropertiesServiceSpreadsheetAppGmailApp)的字样。
  3. 如果服务用于创建界面元素以外的任何用途,请将其移除或封装在注释块中。仅保留以下方法:.getUi().createMenu().addItem().addToUi()。此外,请查找并移除任何不在函数中的服务。
  4. 找出可能包含上一步中注释掉或移除的代码行的函数,尤其是使用这些代码行生成的信息的函数,并将服务调用移至需要这些代码行的函数。重新排列或重写代码库,以适应在上一步中所做的更改。
  5. 保存代码并创建测试部署。

    创建测试部署时,请确保 Config 字段为 Installed for current user(已为当前用户安装),并且 Config 框下方的文本为 Test in AuthMode.None(在 AuthMode.None 中测试)

  6. 启动测试部署,然后打开扩展程序菜单。

  7. 如果所有菜单项均显示,则表示问题已解决。 如果您只看到帮助菜单,请返回第 1 步。 您可能错过了服务通话。