嵌套应用身份验证

注意

嵌套应用身份验证 (NAA) 仅在单页应用程序 (SPA) 中受支持,例如选项卡。

NAA 是一种新的身份验证协议,适用于嵌入在主机环境(如 Teams、Outlook 和 Microsoft 365)中的 SPA。 它简化了身份验证过程,以促进嵌套在受支持的主机应用中的应用之间的单一登录 (SSO) 。 NAA 模型支持主机应用的主要标识,其中包括嵌套应用的多个应用标识。 Microsoft 在 Teams 选项卡、个人应用和 Office 加载项中使用此模型。

与 On-Behalf-Of (OBO) 流相比,NAA 模型具有多项优势:

  • NAA 要求仅使用 MSAL.js 库。 无需在 TeamsJS) (Teams JavaScript 客户端库中使用 getAuthToken 该函数。

  • 可以使用客户端代码中的访问令牌调用 Microsoft Graph 等服务作为 SPA。 不需要中间层服务器。

  • 可对作用域 (权限) 使用增量和动态同意。

  • 无需预先授权主机(如 Teams 或 Microsoft 365)即可调用终结点。

    下表概述了 Teams Microsoft Entra SSO 和 NAA 之间的区别:

    开发所需的步骤 传统 Teams Entra SSO NAA
    公开重定向 URI 必需 必需
    在 Microsoft Entra ID 中注册 API 必需
    在 Microsoft Entra ID 中定义自定义范围 必需
    授权 Teams 客户端应用 必需
    修订应用清单 (以前称为 Teams 应用清单) 必需 推荐*
    通过 TeamsJS SDK 获取访问令牌 必需
    请求用户同意以获得更多权限 必需
    在服务器上进行 OBO 交换 必需
  • IT 管理员可能会阻止应用,或者仅同意 Microsoft Entra ID 中应用的特定权限。 若要避免这种情况,必须在应用清单中包含应用 ID 和默认资源,以便管理员批准 Teams 管理中心的权限。

NAA 的用例

应用场景 说明
同意 SSO (和其他权限) Tom 是 Contoso 设计团队的新成员,他需要在 Teams 会议中使用 Contoso 应用在白板上进行协作。 首次使用时,将显示一个对话框,提示 Tom 授予权限,包括读取其虚拟形象的个人资料 (User.Read) 。 同意后,Tom 可以在将来的跨设备会议中无缝使用 Contoso。
重新身份验证或条件访问 step-up auth Tom 在澳大利亚工作时遇到条件访问触发器,需要多重身份验证 (MFA) 才能访问 Teams 中的 Contoso。 一个对话框通知 Tom 需要进行更多验证,引导他们完成 MFA 过程以继续使用 Contoso。
错误 由于检索帐户信息时出现问题,Tom 面临 Contoso 的登录错误。 Tom 遇到提示重新身份验证的重试按钮。 但是,他们发现系统管理员限制了对 Contoso 的访问权限。

配置 NAA

要配置嵌套身份验证,请执行以下步骤:

  1. 注册 SPA
  2. 添加受信任的代理
  3. 初始化公共客户端应用
  4. 获取第一个令牌
  5. 调用 API

注册 SPA

必须在 Azure 门户上为加载项创建 Microsoft Entra ID 应用注册。 应用注册必须具有名称、支持的帐户类型和 SPA 重定向。 注册应用后,Azure 门户将生成 Microsoft Entra 应用注册 ID。 如果加载项需要除 NAA 和 SSO 之外的其他应用注册,请参阅 注册单页应用程序。.

添加受信任的代理

若要配置嵌套应用身份验证,应用必须主动为应用配置重定向 URI。 重定向 URI 向 Microsoft 标识平台指示你的应用可由受支持的主机进行中转。 应用的重定向 URI 类型必须为 单页应用程序, 并符合以下方案:

brk-multihub://<your_domain>

其中:

  • brk-multihub 使身份验证可由配置为在其中运行的任何 Microsoft 365 支持的主机(例如 Teams、Outlook 或 Microsoft365.com)进行中转。
  • <your_domain> 是托管应用的完全限定域名。 例如, brk-multihub://contoso.com。

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

✔️ brk-multihub://myapp.teams.microsoft.com
❌ brk-multihub://myapp.teams.microsoft.com/go

有关将 Teams 应用升级到 Outlook 和 Microsoft365.com 中运行的详细信息,请参阅在 Microsoft 365 中扩展 Teams 应用。

初始化公共客户端应用

注意

为确保身份验证成功,请在初始化 MSAL 之前初始化 TeamsJS。

初始化 MSAL 并获取公共客户端应用的实例,以便在需要时获取访问令牌。

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

const msalConfig = {
  auth: {
    clientId: "your_client_id",
    authority: "https://login.microsoftonline.com/{your_tenant_id}",
    supportsNestedAppAuth: true
  },
};

let pca: IPublicClientApplication;

export function initializePublicClient() {
  console.log("Starting initializePublicClient");
  return createNestablePublicClientApplication(msalConfig).then(
    (result) => {
      console.log("Client app created");
      pca = result;
      return pca;
    }
  );
}

获取第一个令牌

MSAL.js 通过嵌套应用身份验证获取的令牌是为Microsoft Entra应用注册 ID 颁发的。 MSAL.js 处理用户身份验证的令牌获取。 它尝试以无提示的方式获取访问令牌。 如果未成功,则会提示用户征求同意。 然后,该令牌用于调用 Microsoft 图形 API 或其他受 Microsoft Entra ID 保护的资源。 与 OBO 流不同,您无需预先授权主机调用端点。

若要获取令牌,请执行以下步骤:

  1. 使用 MSAL.js 获取应用 ID 的令牌。 有关详细信息,请参阅 获取和使用访问令牌。

  2. 使用 getActiveAccount API 验证是否有活动帐户来调用 publicClientApplication. 如果没有活动帐户,请尝试使用其他筛选器参数(如 tenantID、 homeAccountId和loginHint上下文界面)从缓存getAccount中检索一个活动帐户。

    注意

    该 homeAccountId 属性等效 userObjectId 于 TeamsJS 中。

  3. 调用 publicClientApplication.acquireTokenSilent(accessTokenRequest) 以无用户交互的方式静默获取令牌。 accessTokenRequest 指定请求访问令牌的范围。 NAA 支持增量和动态同意。 确保始终请求代码完成任务所需的最小范围。

  4. 如果没有可用的帐户,MSAL.js 返回一个 InteractionRequiredAuthError. 调用 publicClientApplication.acquireTokenPopup(accessTokenRequest) 以显示用户的交互式对话。 acquireTokenSilent 如果令牌已过期或用户未同意所有请求的作用域,则可能会失败。

    以下代码段显示一个访问令牌的示例:

    
      // MSAL.js exposes several account APIs, logic to determine which account to use is the responsibility of the developer
      const account = publicClientApplication.getActiveAccount();
    
      const accessTokenRequest = {
      scopes: ["user.read"],
      account: account,
      };
    
      publicClientApplication
        .acquireTokenSilent(accessTokenRequest)
        .then(function (accessTokenResponse) {
          // Acquire token silent success
          let accessToken = accessTokenResponse.accessToken;
          // Call your API with token
          callApi(accessToken);
        })
        .catch(function (error) {
          //Acquire token silent failure, and send an interactive request
          if (error instanceof InteractionRequiredAuthError) {
            publicClientApplication
              .acquireTokenPopup(accessTokenRequest)
              .then(function (accessTokenResponse) {
                // Acquire token interactive success
                let accessToken = accessTokenResponse.accessToken;
                // Call your API with token
                callApi(accessToken);
              })
              .catch(function (error) {
                // Acquire token interactive failure
                console.log(error);
              });
          }
          console.log(error);
        });
    
    

调用 API

收到令牌后,使用它来调用 API。 这可确保使用有效令牌调用 API,以便向服务器发出经过身份验证的请求。

下面的示例演示如何向 Microsoft 图形 API 发出经过身份验证的请求以访问 Microsoft 365 数据:


var headers = new Headers();
var bearer = "Bearer " + access_token;
headers.append("Authorization", bearer);
var options = {
    method: "GET",
    headers: headers
};

var graphEndpoint = "<https://graph.microsoft.com/v1.0/me>";

fetch(graphEndpoint, options)
    .then(function (response) {
        //do something with response
    });

针对嵌套应用身份验证 (NAA) 进行令牌预取

为了提高性能并减少身份验证延迟,嵌套应用身份验证 (NAA) 支持令牌预取。 此功能使主机能够在应用程序启动之前主动获取身份验证令牌,从而允许更快地访问受保护的资源。

如何启用令牌预取

若要启用令牌预提取,请将 Teams 应用清单更新到版本 1.22 或更高版本,并在 nestedAppAuthInfo .webApplicationInfo

{
 "webApplicationInfo": {
   "id": "33333ddd-0000-0000-0000-88888757bbbb",
   "resource": "api://app.com/botid-33333ddd-0000-0000-0000-88888757bbbb",
   "nestedAppAuthInfo": [
     {
       "redirectUri": "brk-multihub://app.com",
       "scopes": ["openid", "profile", "offline_access"],
       "claims": "{\"access_token\":{\"xms_cc\":{\"values\":[\"CP1\"]}}}"
     }
   ]
 }
}

重要

  • 对于每个 NAA 令牌预取请求,在相应nestedAppAuthInfo条目的可选clientId字段中指定代理或应用的 Microsoft Entra ID 注册客户端 ID。 如果提供,此值用于预提取该条目的令牌。 如果某个条目不包含 clientId,主机将用作 webApplicationInfo.id 该条目的 NAA 令牌预取请求的客户端 ID。
  • webApplicationInfo.id 是未指定 clientId 的条目的回退客户端 ID。 它不需要匹配每个入门级 clientId。 如果应用仅webApplicationInfo.id用于 NAA 令牌预提取,则该值必须与用于其实际 NAA 令牌请求的应用的 Microsoft Entra ID 注册的客户端 ID 匹配。
  • 中的 webApplicationInfo.id 值和其中包含 nestedAppAuthInfo 的所有字段必须与应用的运行时 NAA 令牌请求中使用的参数完全匹配。 任何不匹配(例如范围、重定向 URI 或声明中的差异)都将阻止主机从缓存中提供令牌。
  • 预提取的令牌在内存中存储一小段时间,并且仅在应用的初始加载期间使用。 如果应用稍后尝试提取令牌(例如,响应用户操作),则预提取的令牌可能不再可用。 在这种情况下,应用必须使用标准身份验证流启动新的令牌请求。

运作方式

启用令牌预取后,主机环境会尝试在呈现应用之前获取并缓存所需的令牌。 这些令牌存储在内存中,并在启动后立即可供应用使用。

此行为类似于旧版 Teams SSO 模型中的预取功能,其中 getAuthToken API 在选项卡加载期间自动触发。 借助嵌套应用身份验证 (NAA) ,此功能通过清单配置引入,无需后端令牌交换即可提高性能。

NAA 中令牌预取的好处

  • 通过减少应用启动期间的身份验证延迟来提高性能
  • 跨嵌套应用启用单一登录 (SSO) ,无需重复登录

注意

令牌预取目前仅在 Microsoft Teams Web 和桌面客户端中受支持。

最佳做法

  • 尽可能使用静默身份验证:MSAL.js 提供了该 acquireTokenSilent 方法,该方法通过发出无提示令牌请求来处理令牌续订,而不提示用户。 该方法首先在浏览器存储中查找有效的缓存令牌。 如果找不到,则库会发出无提示请求Microsoft Entra ID,并且如果存在活动用户会话 (由Microsoft Entra域) 浏览器中设置的 cookie 确定,则Microsoft Entra ID返回新令牌。 库不会自动调用该 acquireTokenSilent 方法。 建议在 acquireTokenSilent 进行 API 调用之前调用应用,以获取有效的令牌。

    在某些情况下,使用该 acquireTokenSilent 方法获取令牌的尝试会失败。 例如,如果具有 Microsoft Entra ID 的用户会话过期或应用用户acquireTokenSilent更改密码,则失败。 调用交互式获取令牌方法 (acquireTokenPopup) 。

  • 有一个回退:NAA 流提供跨 Microsoft 生态系统的兼容性。 但是,你的应用可能会出现在未更新以支持 NAA 的下层或旧客户端中。 在这种情况下,应用无法支持无缝 SSO,可能需要调用特殊 API 以便与用户交互以打开身份验证对话框。 有关详细信息,请参阅为 选项卡应用启用 SSO。

    注意

    如果使用的是非 Microsoft Entra 标识提供者,则不得使用 NAA,可以改用弹出身份验证。

  • 支持 NAA:并非所有主机应用环境都支持 NAA。 若要验证当前客户端是否支持此功能,可以调用指定的 API 来确定其状态。 如果返回值为 true NAA,则表示支持 NAA,而 false 表示不支持它。

  • 在多个环境中测试应用:如果应用预期可在 Web 视图和浏览器部署中运行,建议在这两个部署环境中测试应用,以确保其行为符合你的预期。 在浏览器中运行的某些 API 可能无法在 Web 视图中运行。

代码示例

示例名称 Description .NET Node.js
嵌套应用身份验证 此示例展示了Microsoft Entra Microsoft Teams 选项卡中的单一登录 (SSO) ,利用“代表 (OBO) ”流代表用户调用Microsoft图形 API。 View View

另请参阅