使用嵌套应用身份验证在 Office 外接程序中启用 SSO

可以将 MSAL.js 库与嵌套应用身份验证配合使用,以使用 Office 外接程序中的 SSO。 与代表 (OBO) 流,使用嵌套应用身份验证具有多个优势。

  • 只需使用 MSAL.js 库,而不需要 getAccessToken Office.js 中的 函数。
  • 可以使用来自客户端代码的访问令牌(作为 SPA)调用 Microsoft Graph 等服务。 无需使用中间层服务器。
  • 可以对范围使用增量和动态许可。
  • 无需 预授权主机 (例如 Teams、Office) 来调用终结点。

NAA 支持的帐户和主机

NAA 支持Microsoft帐户和Microsoft Entra ID (工作/学校) 标识。 它不支持适用于企业到消费者标识管理方案的 Azure Active Directory B2C。 下表按平台说明了当前支持。 (正式发布) 列出的平台已准备好在外接程序中使用。

应用程序 Web Windows Mac iOS/iPad Android
Excel 预览版 预览版 预览版 iPad 上的预览版 不适用
Outlook GA 当前频道中的正式版、所有其他频道中的预览版 GA ga (iOS) GA
PowerPoint 预览版 预览版 预览版 iPad 上的预览版 不适用
Word 预览版 预览版 预览版 iPad 上的预览版 不适用

重要

若要在仍处于预览状态的平台上使用 NAA,请加入 Microsoft 365 预览体验计划 (https://insider.microsoft365.com/join) ,然后选择 当前频道 (预览版) 。 请勿在任何预览平台的生产加载项中使用 NAA。 我们邀请你在测试或开发环境中试用 NAA,并欢迎通过 GitHub 提供有关体验的反馈 (请参阅本页末尾的 反馈 部分) 。

注册单页应用程序

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

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

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

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

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

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

例如,如果在 localhost 服务器上的端口 3000 上测试加载项,则可使用 brk-multihub://localhost:3000 作为重定向值。

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

配置 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) 身份验证库。 我们建议使用最新版本的包 (在上次更新时,它是 3.26.0) 。

    "dependencies": {
        "@azure/msal-browser": "^3.26.0",
        ...
    
  2. 保存并运行 npm install 以安装 @azure/msal-browser

  3. 将以下代码添加到 或 taskpane.ts 文件的顶部taskpane.js。 这将导入 MSAL 浏览器库。

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

初始化公共客户端应用程序

接下来,需要初始化 MSAL 并获取 公共客户端应用程序的实例。 这用于在需要时获取访问令牌。 建议将创建公共客户端应用程序的代码放在 方法中 Office.onReady

  • Office.onReady在函数中,添加对 createNestablePublicClientApplication 的调用,如下所示。 将 Enter_the_Application_Id_Here 占位符替换为之前保存的 Azure 应用 ID。

    let pca = undefined;
    Office.onReady(async (info) => {
      if (info.host) {
        document.getElementById("sideload-msg").style.display = "none";
        document.getElementById("app-body").style.display = "flex";
        document.getElementById("run").onclick = run;
    
        // Initialize the public client application
        pca = await createNestablePublicClientApplication({
          auth: {
            clientId: "Enter_the_Application_Id_Here",
            authority: "https://login.microsoftonline.com/common"
          },
        });
      }
    });
    

注意

前面的代码示例将 授权 设置为 common,这支持工作和学校帐户或个人Microsoft帐户。 如果要配置单个租户或其他帐户类型,请参阅 应用程序配置选项 ,了解其他颁发机构选项。

获取第一个令牌

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 函数替换为以下代码。 代码指定读取用户文件所需的最小范围。

    async function run() {
    // Specify minimum scopes needed for the access token.
    const tokenRequest = {
      scopes: ["Files.Read", "User.Read", "openid", "profile"],
    };
    let accessToken = null;
    
    // TODO 1: Call acquireTokenSilent.
    
    // TODO 2: Call acquireTokenPopup.
    
    // TODO 3: Log error if token still null.
    
    // TODO 4: Call the Microsoft Graph API.
    
    }
    
  2. TODO 1 替换为下面的代码。 此代码调用 acquireTokenSilent 以获取访问令牌。

    try {
      console.log("Trying to acquire token silently...");
      const userAccount = await pca.acquireTokenSilent(tokenRequest);
      console.log("Acquired token silently.");
      accessToken = userAccount.accessToken;
    } catch (error) {
      console.log(`Unable to acquire token silently: ${error}`);
    }
    
  3. TODO 2 替换为下面的代码。 此代码检查是否获取了访问令牌。 否则,它将尝试通过调用 acquireTokenPopup以交互方式获取访问令牌。

    if (accessToken === null) {
      // Acquire token silent failure. Send an interactive request via popup.
      try {
        console.log("Trying to acquire token interactively...");
        const userAccount = await pca.acquireTokenPopup(tokenRequest);
        console.log("Acquired token interactively.");
        accessToken = userAccount.accessToken;
      } catch (popupError) {
        // Acquire token interactive failure.
        console.log(`Unable to acquire token interactively: ${popupError}`);
      }
    }
    
  4. TODO 3 替换为下面的代码。 如果无提示登录和交互式登录都失败,请记录错误并返回。

    // Log error if both silent and popup requests failed.
    if (accessToken === null) {
      console.error(`Unable to acquire access token.`);
      return;
    }
    

调用 API

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

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

    // 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: 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,你可能需要回退到对用户进行身份验证的备用方法。 通常,你需要将 MSAL SPA 身份验证模式与 Office JS 对话框 API 一起使用。

使用以下代码检查加载加载项时是否支持 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 外接程序中使用 MSAL.js 嵌套应用身份验证 (NAA) 来访问已登录用户的 Microsoft Graph API。 该示例显示已登录用户的姓名和电子邮件。 它还会将用户的 Microsoft OneDrive 帐户中的文件名插入到文档中。
使用嵌套应用身份验证使用 SSO 的 Outlook 外接程序 演示如何在 Outlook 外接程序中使用 MSAL.js 嵌套应用身份验证 (NAA) 来访问已登录用户的 Microsoft Graph API。 该示例显示已登录用户的姓名和电子邮件。 它还会将用户的 Microsoft OneDrive 帐户中的文件名插入到新的邮件正文中。

另请参阅