使用嵌套应用身份验证在 Office 外接程序中启用单一登录

将 MSAL.js 库与嵌套应用身份验证 (NAA) 配合使用,从 Office 外接程序启用单一登录 (SSO) 。 本文中的过程将指导你完成创建应用注册并将代码添加到项目以使用 NAA。

NAA 支持的帐户和主机

NAA 支持Microsoft帐户和Microsoft Entra ID (工作/学校) 标识。 对于企业到使用者标识管理方案,它不支持 Azure Active Directory B2C。 有关 NAA 要求的详细信息,请参阅 嵌套应用身份验证要求集

注册单页应用程序

你需要在Azure 门户上为加载项创建Microsoft Azure 应用注册。 应用注册必须至少具有以下条件:

  • 名称
  • 支持的帐户类型
  • NAA 的 SPA 重定向

如果外接程序需要 NAA 和 SSO 以外的其他应用注册,请参阅 单页应用程序:应用注册

通过 SPA 重定向添加受信任的代理

若要启用 NAA,应用注册必须包含特定的重定向 URI,以向Microsoft 标识平台指示加载项允许自己由受支持的主机代理。 应用程序的重定向 URI 必须为 单页应用程序 类型,并且符合以下方案。

brk-multihub://your-add-in-domain

域必须仅包含源,而不能包含其子路径。 例如:

✔️ brk-multihub://localhost:3000
✔️ brk-multihub://www.contoso.com
❌ brk-multihub://www.contoso.com/go

受信任的代理组在设计上是动态的,将来可以更新,以包括加载项可能使用 NAA 流的其他主机。 目前,brk-multihub 组包括 Word、Excel、PowerPoint、Outlook 和 Teams (,用于在) 内激活 Office。

重要

对于Word、Excel 和 PowerPoint web 版,还需要额外的重定向,因为浏览器使用标准身份验证流。 SPA 重定向 URI 必须引用 HTML 页,你将在其中使用 MSAL.js 库通过 NAA 请求令牌。

使用以下步骤为 Office 外接程序设置应用注册。

  1. 使用 Microsoft 365 租户的管理员凭据登录到 Azure 门户。 例如,MyName@contoso.onmicrosoft.com

  2. 选择“应用注册”。 如果未看到图标,请在搜索栏中搜索“应用注册”。

    Azure 门户主页。

    将显示 应用注册 页。

  3. 选择“新注册”

    “应用注册”窗格中的新注册。

    将显示注册应用程序页。

  4. 在“注册应用”页上,按如下方式设置值。

    • 将“名称”设置为“contoso-office-add-in-sso”。
    • 将“支持的帐户类型”设置为“任何组织目录中的帐户类型 (任何Azure AD 目录 - 多租户) 和个人Microsoft帐户 (例如 Skype、Xbox)
    • 重定向 URI 设置为使用平台 单页应用程序 (SPA) ,并将 URI 设置为 brk-multihub://localhost:3000。 此重定向假定你正在从 localhost 服务器测试加载项。

    注册一个应用程序窗格,其中完成了名称和支持的帐户。

  5. 选择“注册”。 显示一条消息,指出已创建应用程序注册。

    指示已创建应用程序注册的消息。

  6. 复制并保存 应用程序 (客户端) ID 的值。 将在后续过程中用到它。

    显示客户端 ID 和目录 ID 的 Contoso 的应用注册窗格。

如果外接程序支持 Word、Excel 或 PowerPoint web 版,则必须为任务窗格页面添加 SPA 重定向 URI。 使用以下步骤为任务窗格页添加 SPA 重定向 URI。

  1. 在左窗格中,选择“ 管理 > 身份验证”。 Azure应用注册中的身份验证页。
  2. “平台配置 ”部分中,有 单页应用程序重定向 URI 的列表。
  3. 选择“ 添加 URI”。 选择“Azure应用注册”页上的“添加 URI”选项。
  4. 输入 https://localhost:3000/taskpane.html 并选择“ 保存”。 此重定向 URI 假定你正在使用文件中的 taskpane.html NAA。 在Azure应用注册页上添加任务窗格重定向 URI。

配置 MSAL 配置以使用 NAA

通过在 MSAL 中调用 createNestablePublicClientApplication 函数,将外接程序配置为使用 NAA。 MSAL 返回可嵌套在本机应用程序主机中的公共客户端应用程序, (例如,Outlook) 获取应用程序的令牌。

以下步骤演示如何在使用 taskpane.js (Office 外接程序任务窗格项目) 生成的yo office项目中的 或 taskpane.ts 文件中启用 NAA。

  1. @azure/msal-browser 包添加到 dependencies 项目的 文件的 部分 package.json 。 有关此包的详细信息,请参阅 适用于 Browser-Based Single-Page 应用程序的 Microsoft JavaScript (MSAL.js) 身份验证库。 若要安装最新版本,请运行以下命令。

    npm install @azure/msal-browser
    
  2. 将以下代码添加到 或 taskpane.ts 文件的顶部taskpane.js。 这将导入 MSAL 浏览器库。

    import { createNestablePublicClientApplication, InteractionRequiredAuthError } from "@azure/msal-browser";
    

Outlook 的以下步骤与 Word、Excel 和 PowerPoint 的步骤不同。 选择与要生成的加载项类型对应的选项卡。

初始化 MSAL 库

接下来,需要初始化 MSAL 并获取 公共客户端应用程序的实例。

将以下代码添加到 taskpane.jstaskpane.ts 文件。 将Enter_the_Application_Id_Here占位符替换为之前保存Azure应用 ID。 关于以下代码说明:

  • 函数 initMsal 通过调用 createNestablePublicClientApplication初始化 MSAL。 这将创建一个支持 Outlok 的 SSO 的可嵌套公共客户端应用程序。
  • 函数 initMsal权限 设置为 common,这支持工作和学校帐户或个人Microsoft帐户。 如果要配置单个租户或其他帐户类型,请参阅 应用程序配置选项 ,了解其他颁发机构选项。
let msalInstance = undefined;

/**
 * Initialize MSAL as a nestable public client application.
  */
async function initMsal() {
  if (!msalInstance) {
    const clientId = "Enter_the_Application_Id_Here";
    const msalConfig = {
      auth: {
        clientId: clientId,
        authority: "https://login.microsoftonline.com/common"
      },
      cache: {
        cacheLocation: "localStorage"
      }
    };
    msalInstance = await createNestablePublicClientApplication(msalConfig);
  }
}

获取第一个令牌

MSAL.js 通过 NAA 获取的令牌将为Azure应用注册 ID 颁发。 在此代码示例中,你将获取Microsoft图形 API的令牌。 如果用户具有具有Microsoft Entra ID则以无提示方式获取令牌。 否则,库会提示用户以交互方式登录。 然后,该令牌用于调用Microsoft图形 API。

以下步骤显示了用于获取令牌的模式。

  1. 指定范围。 NAA 支持增量和动态同意,因此始终请求代码完成其任务所需的最小范围。
  2. 调用 acquireTokenSilent。 这将获取令牌,而无需用户交互。
  3. 如果 acquireTokenSilent 失败,请调用 acquireTokenPopup 以显示用户的交互式对话。 acquireTokenSilent 如果令牌过期,或者用户尚未同意所有请求的范围,则可能会失败。

以下代码演示如何在自己的项目中实现此身份验证模式。

  1. runtaskpane.ts 中的 taskpane.js 函数替换为以下代码。 代码指定读取用户文件所需的最小范围。

    export async function run() {
      await initMsal();
      // Specify minimum scopes needed for the access token.
      const tokenRequest = {
        scopes: ["Files.Read", "User.Read"],
      };
      let accessToken = null;
    
      // TODO 1: Use msalInstance to get an access token.
    
      // TODO 2: Call the Microsoft Graph API.
    }
    

    重要

    令牌请求必须包含范围,而不仅仅是 offline_accessopenidprofileemail。 可以使用上述范围的任意组合,但必须至少包含一个附加范围。 否则,令牌请求可能会失败。

  2. TODO 1 替换为下面的代码。 此代码调用 acquireTokenSilent 以获取访问令牌。

    try {
      const userAccount = await msalInstance.acquireTokenSilent(tokenRequest);
      console.log("Acquired token silently.");
      accessToken = userAccount.accessToken;
    } catch (silentError) {
      // TODO 1a: Handle acquireTokenSilent failure.
    
    }
    
  3. TODO 1a 替换为下面的代码。 此代码检查是否 acquireTokenSilentInteractionRequiredAuthError出 。 如果是这样,代码将调用 acquireTokenPopup ,以便 MSAL 可以使用弹出对话框与用户交互。 由于各种原因(例如完成多重授权),可能需要交互。

    if (silentError instanceof InteractionRequiredAuthError) {
      console.log(`Unable to acquire token silently: ${silentError}`);
      // Silent acquisition failed. Continue to interactive acquisition.
      try {
        const userAccount = await msalInstance.acquireTokenPopup(tokenRequest);
        console.log("Acquired token interactively.");
        accessToken = userAccount.accessToken;
      } catch (popupError) {
        // Acquire token interactive failure.
        console.error(`Unable to acquire token interactively: ${popupError}`);
        return;
      }
    } else {
      // Acquire token silent failure. Error can't be resolved through interaction.
      console.error(`Unable to acquire token silently: ${silentError}`);
      return;
    }
    

调用 API

获取令牌后,使用它调用 API。 以下示例演示如何使用 Authorization 标头中附加的令牌调用 fetch Microsoft 图形 API。

  • TODO 2 替换为下面的代码。

    // Call the Microsoft Graph API with the access token.
    const response = await fetch(
      `https://graph.microsoft.com/v1.0/me/drive/root/children?$select=name&$top=10`,
      {
        headers: { Authorization: `Bearer ${accessToken}` },
      }
    );
    
    if (response.ok) {
      // Write file names to the console.
      const data = await response.json();
      const names = data.value.map((item) => item.name);
    
      // Be sure the taskpane.html has an element with Id = item-subject.
      const label = document.getElementById("item-subject");
    
      // Write file names to task pane and the console.
      const nameText = names.join(", ");
      if (label) label.textContent = nameText;
      console.log(nameText);
    } else {
      const errorText = await response.text();
      console.error("Microsoft Graph call failed - error text: " + errorText);
    }
    

将上述所有代码添加到 run 函数后,请确保任务窗格上的按钮调用函数 run 。 然后,你可以旁加载加载项并试用代码。

什么是嵌套应用身份验证

嵌套应用身份验证为嵌套在受支持的Microsoft应用程序内的应用程序启用 SSO。 例如,Windows 上的 Excel 在 Web 视图中运行加载项。 在此方案中,外接程序是在 Excel(主机)中运行的嵌套应用程序。 NAA 还支持 Teams 中的嵌套应用。 例如,如果 Teams 选项卡托管 Excel,并且加载了加载项,则它将嵌套在 Excel 中,Excel 中也嵌套在 Teams 中。 同样,NAA 支持此嵌套方案,你可以访问 SSO 来获取已登录用户的用户标识和访问令牌。

最佳做法

将 MSAL.js 与 NAA 配合使用时,建议采用以下最佳做法。

尽可能使用无提示身份验证

MSAL.js 提供了一种方法, acquireTokenSilent 该方法通过发出无提示令牌请求来处理令牌续订,而无需提示用户。 方法首先查找有效的缓存令牌。 如果找不到,库会向Microsoft Entra ID发出无提示请求,如果存在活动用户会话,则会返回新的令牌。

在某些情况下, acquireTokenSilent 方法获取令牌的尝试会失败。 例如,存在一个过期的用户会话与Microsoft Entra ID或用户更改密码,这需要用户交互。 当 acquireTokenSilent 失败时,需要调用交互式 acquireTokenPopup 令牌方法。

当 NAA 不受支持时进行回退

虽然我们努力在整个Microsoft生态系统中提供与这些流的高度兼容性,但您的外接程序可能加载到不支持 NAA 的旧版 Office 主机中。 在这些情况下,加载项不支持无缝 SSO,你可能需要回退到对用户进行身份验证的备用方法。 有关演示如何处理回退方案的示例,请参阅本文中的 代码示例

使用以下代码检查加载加载项时是否支持 NAA。

   Office.context.requirements.isSetSupported("NestedAppAuth", "1.1");

有关详细信息,请参阅以下资源。

NAA 支持的 MSAL.js API

下表显示了在 MSAL 配置中启用 NAA 时支持哪些 API。

方法 受 NAA 支持
acquireTokenByCode 无 (引发异常)
acquireTokenPopup
acquireTokenRedirect 无 (引发异常)
acquireTokenSilent
addEventCallback
addPerformanceCallback 无 (引发异常)
disableAccountStorageEvents 无 (引发异常)
enableAccountStorageEvents 无 (引发异常)
getAccountByHomeId
getAccountByLocalId
getAccountByUsername
getActiveAccount
getAllAccounts
getConfiguration
getLogger
getTokenCache 无 (引发异常)
handleRedirectPromise
initialize
initializeWrapperLibrary
loginPopup
loginRedirect 无 (引发异常)
logout 无 (引发异常)
logoutPopup 无 (引发异常)
logoutRedirect 无 (引发异常)
removeEventCallback
removePerformanceCallback 无 (引发异常)
setActiveAccount
setLogger
ssoSilent

安全报告

如果发现我们的库或服务存在安全问题,请尽可能详细地向报告问题 secure@microsoft.com 。 你的提交可能有资格通过Microsoft赏金计划获得 赏金 。 请勿将安全问题发布到 GitHub 或任何其他公共站点。 收到问题报告后,我们会立即联系你。 我们鼓励你通过访问 Microsoft技术安全通知 来获取新的安全事件通知,以订阅安全咨询警报。

代码示例

示例名称 Description
使用嵌套应用身份验证进行 SSO 的 Office 外接程序 演示如何在 Office 外接程序中使用 NAA 访问已登录用户的 Microsoft Graph API。
使用嵌套应用身份验证使用 SSO 的 Outlook 外接程序 演示如何在 Outlook 外接程序中使用 NAA 访问已登录用户的 Microsoft Graph API。
使用嵌套应用身份验证在 Outlook 加载项中的事件中实现 SSO 演示如何在 Outlook 外接程序事件中使用 NAA 和 SSO。
使用嵌套应用身份验证 (NAA) 和 SSO 将标识声明发送到资源 演示如何将已登录用户的标识声明 ((例如名称、电子邮件或唯一 ID) )发送到数据库等资源。 此示例替换旧版Exchange Online令牌的过时模式。

另请参阅