授权范围

用户必须授权脚本项目访问其数据或代表其执行操作。当用户首次运行需要授权的脚本时,界面会显示一个提示,以启动授权流程。

在此流程中,界面会告知用户脚本想要执行哪些操作的权限。例如,脚本可能需要权限来读取用户的电子邮件或在其日历中创建活动。脚本项目将这些单独的权限定义为 OAuth 范围

对于大多数脚本,Apps 脚本会自动检测您需要哪些作用域;您可以随时查看脚本使用的作用域。您还可以使用网址字符串在manifest明确设置范围。某些应用(例如插件)有时需要明确设置镜重,因为已发布的应用应始终使用尽可能窄的镜重。

在授权流程中,Apps Script 会向用户显示所需范围的人类可读说明。例如,如果脚本需要对电子表格拥有只读权限,清单的范围可能为 https://www.googleapis.com/auth/spreadsheets.readonly。在授权流程中,具有此范围的脚本会请求用户允许此应用“查看您的 Google 电子表格”。

有些镜重包含其他镜重。例如,授权后,范围 https://www.googleapis.com/auth/spreadsheets 会允许对电子表格进行读写访问。

对于运行脚本的某些界面(例如直接从 Apps Script IDE 运行脚本),系统会向用户显示精细的 OAuth 权限请求页面。这样,用户可以选择要授予的具体权限,而不是一次性授予所有权限。请务必设计脚本以处理精细的 OAuth 权限

查看范围

您可以执行以下操作,查看脚本项目当前需要的范围:

  1. 打开脚本项目。
  2. 点击左侧的概览 icon
  3. Project OAuth Scopes(项目 OAuth 范围)下查看相应范围。

设置显式镜重

Apps Script 会扫描脚本代码,找出需要相应作用域的函数调用,从而自动确定脚本需要哪些作用域。对于大多数脚本,这已足够,而且可以节省您的时间,但对于已发布的插件、Web 应用、Google Chat 应用以及对 Google Chat API 的调用,您必须更直接地控制这些范围。

Apps 脚本有时会自动为项目分配非常宽松的镜重。这可能意味着您的脚本向用户索取的权限超出了其需要的权限,这是一种不良做法。对于已发布的脚本,您必须将广泛的范围替换为仅涵盖脚本所需内容的更有限的范围。

您可以通过修改脚本项目的manifest文件来明确设置脚本项目使用的范围。清单字段 oauthScopes 是项目使用的所有镜的数组。如需设置项目的镜重范围,请执行以下操作:

  1. 打开脚本项目。
  2. 点击左侧的项目设置
  3. 选中在编辑器中显示“appsscript.json”清单文件复选框。
  4. 点击左侧的编辑器图标
  5. 点击左侧的 appsscript.json 文件。
  6. 找到标记为 oauthScopes 的顶级字段。如果没有,您可以添加。
  7. oauthScopes 字段指定一个字符串数组。如需设置项目使用的镜重,请将此数组的内容替换为您希望项目使用的镜重。例如:
          {
            ...
            "oauthScopes": [
              "https://www.googleapis.com/auth/spreadsheets.readonly",
              "https://www.googleapis.com/auth/userinfo.email"
            ],
           ...
          }
  8. 点击顶部的“保存”图标

处理精细的 OAuth 权限

借助精细的 OAuth 权限请求页面,用户可以指定他们想要授予哪些个别 OAuth 范围。精细的 OAuth 权限可让用户更精细地控制他们选择与每个脚本共享哪些账号数据。例如,假设您开发了一个脚本,该脚本请求同时获取电子邮件和日历镜重范围的权限。您的用户可能只希望使用您的脚本在 Google 日历中执行操作,而不希望在 Gmail 中执行操作。借助精细的 OAuth 权限,用户可以选择仅授予 Google 日历权限,而不授予 Gmail 权限。

以下部分介绍了处理精细 OAuth 权限的主要方法。

自动要求获取必要范围的权限

如果某个执行流程需要权限才能正常运行,您可以要求用户先授予这些权限,然后才能使用该流程。您的脚本可以检查用户是否已授予权限,如果未授予,则自动向用户请求权限。

借助 ScriptApp中的以下方法,您可以验证对所需镜区的权限,并自动呈现授权提示以请求缺少的任何权限:

示例

以下示例展示了如何调用 requireScopes(authMode, oAuthScopes)requireAllScopes(authMode) 方法。该脚本使用 Gmail、表格和日历的范围。sendEmail() 函数仅需要 Gmail 和 Google 表格的权限范围,而 createEventSendEmail() 函数需要脚本使用的所有权限范围。

// This function requires the Gmail and Sheets scopes.
function sendEmail() {
  // Validates that the user has granted permission for the Gmail and Sheets scopes.
  // If not, the execution ends and prompts the user for authorization.
  ScriptApp.requireScopes(ScriptApp.AuthMode.FULL, [
    'https://mail.google.com/',
    'https://www.googleapis.com/auth/spreadsheets'
  ]);

  // Sends an email.
  GmailApp.sendEmail("dana@example.com", "Subject", "Body");
  Logger.log("Email sent successfully!");

  // Opens a spreadsheet and sheet to track the sent email.
  const ss = SpreadsheetApp.openById("abc1234567");
  const sheet = ss.getSheetByName("Email Tracker")

  // Gets the last row of the sheet.
  const lastRow = sheet.getLastRow();

  // Adds "Sent" to column E of the last row of the spreadsheet.
  sheet.getRange(lastRow, 5).setValue("Sent");
  Logger.log("Sheet updated successfully!");
}

// This function requires all scopes used by the script (Gmail,
// Calendar, and Sheets).
function createEventSendEmail() {
  // Validates that the user has granted permission for all scopes used by the
  // script. If not, the execution ends and prompts the user for authorization.
  ScriptApp.requireAllScopes(ScriptApp.AuthMode.FULL);

  // Creates an event.
  CalendarApp.getDefaultCalendar().createEvent(
    "Meeting",
    new Date("November 28, 2024 10:00:00"),
    new Date("November 28, 2024 11:00:00")
  );
  Logger.log("Calendar event created successfully!");

  // Sends an email.
  GmailApp.sendEmail("dana@example.com", "Subject 2", "Body 2");
  Logger.log("Email sent successfully!");

  // Opens a spreadsheet and sheet to track the created meeting and sent email.
  const ss = SpreadsheetApp.openById("abc1234567");
  const sheet = ss.getSheetByName("Email and Meeting Tracker")
  // Gets the last row
  const lastRow = sheet.getLastRow();

  // Adds "Sent" to column E of the last row
  sheet.getRange(lastRow, 5).setValue("Sent");
  // Adds "Meeting created" to column F of the last row
  sheet.getRange(lastRow, 6).setValue("Meeting created");
  Logger.log("Sheet updated successfully!");
}

为缺少的镜重创建自定义体验

您可以获取运行脚本的用户的权限详细信息,并根据其权限状态设计自定义体验。例如,您可以决定停用脚本中需要用户未授予的权限的特定功能,或者显示自定义对话框来说明缺少的权限。以下方法会获取包含用户权限信息的对象,其中包括用户已授权的镜重范围以及用于请求任何缺失镜重范围的网址:

如需从授权信息对象获取权限详细信息(例如已授权的镜重范围的列表和用于请求缺失权限的网址),请使用 AuthorizationInfo中的方法。

示例

以下示例展示了如何调用 getAuthorizationInfo(authMode, oAuthScopes) 方法,以在未授予所需镜的情况下跳过执行流程中的特定功能。这样,执行流程的其余部分便可继续,而无需提示用户授予缺少的镜重范围的权限。

// This function uses the Gmail scope and skips the email
// capabilities if the scope for Gmail hasn't been granted.
function myFunction() {
  const authInfo = ScriptApp.getAuthorizationInfo(ScriptApp.AuthMode.FULL, ['https://mail.google.com/']);
  if (authInfo.getAuthorizationStatus() === ScriptApp.AuthorizationStatus.NOT_REQUIRED) {
    GmailApp.sendEmail("dana@example.com", "Subject", "Body");
    Logger.log("Email sent successfully!");
  } else {
    const scopesGranted = ScriptApp.getAuthorizationInfo(ScriptApp.AuthMode.FULL).getAuthorizedScopes();
    console.warn(`Authorized scopes: ${scopesGranted} not enough to send mail, skipping.`);
  }
  // Continue the rest of the execution flow...
}

OAuth 验证

某些 OAuth 范围属于敏感范围,因为它们允许访问 Google 用户数据。如果您的脚本项目使用允许访问用户数据的范围,则必须先通过 OAuth 客户端验证,然后才能将其作为 Web 应用或插件公开发布。如需了解详情,请参阅以下指南:

受限范围

除了敏感范围之外,某些范围还被归类为受限范围,并受助于保护用户数据的其他规则约束。如果您打算发布使用一个或多个受限范围的 Web 应用或插件,则该应用必须遵守所有指定的限制,然后才能发布。

在尝试发布之前,请先查看受限镜区的完整列表。如果您的应用使用了其中任何一个,您必须在发布前遵守有关特定 API 范围的其他要求