Azure Active Directory 条件访问开发人员指南Developer guidance for Azure Active Directory Conditional Access

保护应用安全和保护服务的方法有多种,Azure Active Directory (Azure AD) 中的条件访问功能便是其中之一。The Conditional Access feature in Azure Active Directory (Azure AD) offers one of several ways that you can use to secure your app and protect a service. 通过条件访问功能,可以让开发人员和企业客户以多种方式保护服务的安全,其中包括:Conditional Access enables developers and enterprise customers to protect services in a multitude of ways including:

  • 多重身份验证Multi-factor authentication
  • 仅允许已注册 Intune 的设备访问特定服务Allowing only Intune enrolled devices to access specific services
  • 限制用户位置和 IP 范围Restricting user locations and IP ranges

有关条件访问完整功能的详细信息,请参阅什么是条件访问一文。For more information on the full capabilities of Conditional Access, see the article What is Conditional Access.

对于构建 Azure AD 应用的开发人员,本文演示了条件访问的使用方法,并介绍了访问应用了条件访问策略且你无权控制的资源时将产生的影响。For developers building apps for Azure AD, this article shows how you can use Conditional Access and you'll also learn about the impact of accessing resources that you don't have control over that may have Conditional Access policies applied. 此外,本文还探讨了条件访问对代理流、Web 应用、访问 Microsoft Graph 和调用 API 的影响。The article also explores the implications of Conditional Access in the on-behalf-of flow, web apps, accessing Microsoft Graph, and calling APIs.

本文假定已了解单租户多租户应用以及常见的身份验证模式Knowledge of single and multi-tenant apps and common authentication patterns is assumed.

备注

使用此功能需要 Azure AD Premium P1 许可证。Using this feature requires an Azure AD Premium P1 license. 若要根据需要查找合适的许可证,请参阅比较免费版、基本版和高级版的正式发布功能To find the right license for your requirements, see Comparing generally available features of the Free, Basic, and Premium editions. 拥有 Microsoft 365 商业版许可证的客户也可以访问条件访问功能。Customers with Microsoft 365 Business licenses also have access to Conditional Access features.

条件访问对应用有何影响?How does Conditional Access impact an app?

受影响的应用类型App types impacted

通常,在多数情况下,条件访问不会更改应用的行为或要求开发人员进行任何更改。In most common cases, Conditional Access does not change an app's behavior or requires any changes from the developer. 只有在特定情况下(应用以间接方式或无提示的方式请求服务令牌时),应用才需要进行代码更改以处理条件访问“质询”。 Only in certain cases when an app indirectly or silently requests a token for a service, an app requires code changes to handle Conditional Access "challenges". 此过程可能与执行交互式登录请求一样简单。 It may be as simple as performing an interactive sign-in request.

具体来说,在以下应用场景下要求代码处理条件访问“质询”:Specifically, the following scenarios require code to handle Conditional Access "challenges":

  • 执行代理流的应用Apps performing the on-behalf-of flow
  • 访问多个服务/资源的应用Apps accessing multiple services/resources
  • 使用 MSAL.js 的单页应用Single-page apps using MSAL.js
  • 调用资源的 Web 应用Web Apps calling a resource

条件访问策略不仅可应用于应用,还可应用于应用访问的 Web API。Conditional Access policies can be applied to the app, but also can be applied to a web API your app accesses. 若要详细了解如何配置条件访问策略,请参阅快速入门:使用 Azure Active Directory 条件访问要求针对特定应用进行 MFATo learn more about how to configure a Conditional Access policy, see Quickstart: Require MFA for specific apps with Azure Active Directory Conditional Access.

根据具体的情况,企业客户随时可以应用和删除条件访问策略。Depending on the scenario, an enterprise customer can apply and remove Conditional Access policies at any time. 应用新策略后,若要使应用继续正常工作,需执行“质询”处理。In order for your app to continue functioning when a new policy is applied, you need to implement the "challenge" handling. 以下示例演示了质询处理的过程。The following examples illustrate challenge handling.

条件访问示例Conditional Access examples

在某些应用场景下,需要进行代码更改来处理条件访问,而在其他应用场景下一切按原样运行。Some scenarios require code changes to handle Conditional Access whereas others work as is. 下面是使用条件访问执行多重身份验证的一些应用场景,可以通过它们深入了解其中的差异。Here are a few scenarios using Conditional Access to do multi-factor authentication that gives some insight into the difference.

  • 你正在构建单租户 iOS 应用,并应用了条件访问策略。You are building a single-tenant iOS app and apply a Conditional Access policy. 应用允许用户登录且不请求访问 API。The app signs in a user and doesn't request access to an API. 用户登录后,自动调用策略,用户需要执行多重身份验证 (MFA)。When the user signs in, the policy is automatically invoked and the user needs to perform multi-factor authentication (MFA).
  • 你正在构建使用中间层服务访问下游 API 的本机应用。You are building a native app that uses a middle tier service to access a downstream API. 公司中使用此应用的企业客户对下游 API 应用了策略。An enterprise customer at the company using this app applies a policy to the downstream API. 最终用户登录时,本机应用将请求访问中间层并将发送令牌。When an end user signs in, the native app requests access to the middle tier and sends the token. 中间层执行代理流来请求访问下游 API。The middle tier performs on-behalf-of flow to request access to the downstream API. 此时,将向中间层发出一个声明“质询”。At this point, a claims "challenge" is presented to the middle tier. 中间层将质询发送回本机应用,本机应用需符合条件访问策略。The middle tier sends the challenge back to the native app, which needs to comply with the Conditional Access policy.

Microsoft GraphMicrosoft Graph

在条件访问环境中构建应用时,Microsoft Graph 具有特殊注意事项。Microsoft Graph has special considerations when building apps in Conditional Access environments. 一般来说,条件访问的机制是相同的,但是用户看到的策略将基于应用程序从图形中请求的基础数据。Generally, the mechanics of Conditional Access behave the same, but the policies your users see will be based on the underlying data your app is requesting from the graph.

具体来说,所有 Microsoft Graph 范围都表示可以单独应用策略的某些数据集。Specifically, all Microsoft Graph scopes represent some dataset that can individually have policies applied. 由于条件访问策略分配给了特定的数据集,Azure AD 将基于图形背后的数据而不是图形本身强制实施条件访问策略。Since Conditional Access policies are assigned the specific datasets, Azure AD will enforce Conditional Access policies based on the data behind Graph - rather than Graph itself.

例如,如果某个应用程序请求下列 Microsoft Graph 范围,For example, if an app requests the following Microsoft Graph scopes,

scopes="Bookings.Read.All Mail.Read"

应用可能期望其用户完成所有关于预订和交换的策略。An app can expect their users to fulfill all policies set on Bookings and Exchange. 如果授予访问权限,某些范围可能映射到多个数据集。Some scopes may map to multiple datasets if it grants access.

符合条件访问策略Complying with a Conditional Access policy

对于多个不同的应用拓扑,会在建立会话时评估条件访问策略。For several different app topologies, a Conditional Access policy is evaluated when the session is established. 条件访问策略在应用和服务粒度级别运行时,调用它的时间很大程度上取决于你尝试完成的应用场景。As a Conditional Access policy operates on the granularity of apps and services, the point at which it is invoked depends heavily on the scenario you're trying to accomplish.

在应用尝试访问具有条件访问策略的服务时,可能会遇到条件访问质询。When your app attempts to access a service with a Conditional Access policy, it may encounter a Conditional Access challenge. 此质询编码在 claims 参数中,而此参数来自 Azure AD 的响应。This challenge is encoded in the claims parameter that comes in a response from Azure AD. 以下是此质询参数的示例:Here's an example of this challenge parameter:

claims={"access_token":{"polids":{"essential":true,"Values":["<GUID>"]}}}

开发人员可以接受此质询并将其追加到新的 Azure AD 请求中。Developers can take this challenge and append it onto a new request to Azure AD. 传递此状态将提示最终用户执行任何必要的操作以符合条件访问策略。Passing this state prompts the end user to perform any action necessary to comply with the Conditional Access policy. 以下应用场景说明了错误的详细信息及如何提取此参数。In the following scenarios, specifics of the error and how to extract the parameter are explained.

方案Scenarios

先决条件Prerequisites

Azure AD 条件访问是 Azure AD Premium 包含的一项功能。Azure AD Conditional Access is a feature included in Azure AD Premium. 拥有 Microsoft 365 商业版许可证的客户也可以访问条件访问功能。Customers with Microsoft 365 Business licenses also have access to Conditional Access features.

特定应用场景的注意事项Considerations for specific scenarios

下列信息仅适用于这些条件访问应用场景:The following information only applies in these Conditional Access scenarios:

  • 执行代理流的应用Apps performing the on-behalf-of flow
  • 访问多个服务/资源的应用Apps accessing multiple services/resources
  • 使用 MSAL.js 的单页应用Single-page apps using MSAL.js

以下各部分讨论更复杂的常见应用场景。The following sections discuss common scenarios that are more complex. 核心运行原则是请求已应用条件访问策略的服务令牌时评估条件访问策略。The core operating principle is Conditional Access policies are evaluated at the time the token is requested for the service that has a Conditional Access policy applied.

方案:执行代理流的应用Scenario: App performing the on-behalf-of flow

在此应用场景中,我们将演示本机应用调用 Web 服务/API 时的场景。In this scenario, we walk through the case in which a native app calls a web service/API. 而此服务又会执行“代理”流来调用下游服务。In turn, this service does the "on-behalf-of" flow to call a downstream service. 在本示例中,我们已向下游服务 (Web API 2) 应用了条件访问策略,并且使用的是本机应用,而非服务器/守护程序应用。In our case, we've applied our Conditional Access policy to the downstream service (Web API 2) and are using a native app rather than a server/daemon app.

执行代理流的应用示意图

Web API 1 的初始令牌请求未提示最终用户进行多重身份验证,因为 Web API 1 不会始终命中下游 API。The initial token request for Web API 1 does not prompt the end user for multi-factor authentication as Web API 1 may not always hit the downstream API. Web API 1 尝试代表 Web API 2 的用户请求令牌时,请求会失败,因为此用户尚未使用多重身份验证进行登录。Once Web API 1 tries to request a token on-behalf-of the user for Web API 2, the request fails since the user has not signed in with multi-factor authentication.

Azure AD 返回 HTTP 响应,其中包含一些有价值的数据:Azure AD returns an HTTP response with some interesting data:

备注

在此实例中,这些数据是多重身份验证错误说明,但很大一部分的 interaction_required 可能与条件访问有关。In this instance it's a multi-factor authentication error description, but there's a wide range of interaction_required possible pertaining to Conditional Access.

HTTP 400; Bad Request
error=interaction_required
error_description=AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access '<Web API 2 App/Client ID>'.
claims={"access_token":{"polids":{"essential":true,"Values":["<GUID>"]}}}

在 Web API 1 中,我们捕获到错误 error=interaction_required,并向桌面应用发送回 claims 质询。In Web API 1, we catch the error error=interaction_required, and send back the claims challenge to the desktop app. 此时,桌面应用可以发出新的 acquireToken() 调用并将 claims 质询追加为额外的查询字符串参数。At that point, the desktop app can make a new acquireToken() call and append the claimschallenge as an extra query string parameter. 这个新请求需要用户执行多重身份验证,然后将此新令牌发送回 Web API 1,并完成代理流。This new request requires the user to do multi-factor authentication and then send this new token back to Web API 1 and complete the on-behalf-of flow.

若要尝试此应用场景,请参阅 .NET 代码示例To try out this scenario, see our .NET code sample. 它演示了如何将声明质询从 Web API 1 传送回本机应用,以及如何在客户端应用内构造新请求。It demonstrates how to pass the claims challenge back from Web API 1 to the native app and construct a new request inside the client app.

方案:访问多个服务的应用Scenario: App accessing multiple services

在此方案中,我们将演示 Web 应用访问两个服务且其中之一已分配条件访问策略时的场景。In this scenario, we walk through the case in which a web app accesses two services one of which has a Conditional Access policy assigned. 可能存在应用无需访问两个 Web 服务的方法,具体要取决于应用逻辑。Depending on your app logic, there may exist a path in which your app does not require access to both web services. 在此应用场景中,请求令牌的顺序对最终用户体验有重要影响。In this scenario, the order in which you request a token plays an important role in the end-user experience.

假定有 Web 服务 A 和 Web 服务 B,且 Web 服务 B 已应用了条件访问策略。Let's assume we have web service A and B and web service B has our Conditional Access policy applied. 虽然初始交互式身份验证请求需要两个服务的同意,但是并非在所有情况都需要条件访问策略。While the initial interactive auth request requires consent for both services, the Conditional Access policy is not required in all cases. 如果应用请求 Web 服务 B 的令牌,则将调用策略,并且对 Web 服务 A 的后续请求也将成功,如下所示。If the app requests a token for web service B, then the policy is invoked and subsequent requests for web service A also succeeds as follows.

访问多个服务流的应用示意图

或者,如果应用最初请求 Web 服务 A 的令牌,则最终用户将不会调用条件访问策略。Alternatively, if the app initially requests a token for web service A, the end user does not invoke the Conditional Access policy. 这样应用开发人员可以控制最终用户体验,且无需在所有情况下强制调用条件访问策略。This allows the app developer to control the end-user experience and not force the Conditional Access policy to be invoked in all cases. 最复杂的情况是应用随后请求 Web 服务 B 的令牌。此时,最终用户需要符合条件访问策略。The tricky case is if the app subsequently requests a token for web service B. At this point, the end user needs to comply with the Conditional Access policy. 应用尝试 acquireToken 时,可能会生成以下错误(如下图所示):When the app tries to acquireToken, it may generate the following error (illustrated in the following diagram):

HTTP 400; Bad Request
error=interaction_required
error_description=AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access '<Web API App/Client ID>'.
claims={"access_token":{"polids":{"essential":true,"Values":["<GUID>"]}}}

访问多个请求新令牌的服务的应用

如果应用使用 MSAL 库,则会始终以交互方式重新尝试获取令牌并失败。If the app is using the MSAL library, a failure to acquire the token is always retried interactively. 发生此交互式请求时,最终用户有机会符合条件访问策略。When this interactive request occurs, the end user has the opportunity to comply with the Conditional Access. 上述说法是正确的,但当请求是 AcquireTokenSilentAsyncPromptBehavior.Never 时,应用需要执行交互式 AcquireToken 请求来为最终用户提供符合策略的机会。This is true unless the request is a AcquireTokenSilentAsync or PromptBehavior.Never in which case the app needs to perform an interactive AcquireToken request to give the end user the opportunity to comply with the policy.

方案:使用 MSAL.js 的单页应用 (SPA)Scenario: Single-page app (SPA) using MSAL.js

在此方案中,我们将演示单页应用 (SPA) 使用 MSAL.js 调用由条件访问保护的 Web API 时的场景。In this scenario, we walk through the case when we have a single-page app (SPA), using MSAL.js to call a Conditional Access protected web API. 这是一个简单的体系结构,但围绕条件访问进行开发时需要注意其中的一些细微差异。This is a simple architecture but has some nuances that need to be taken into account when developing around Conditional Access.

在 MSAL.js 中,有多个获取令牌的函数:loginPopup()acquireTokenSilent(...)acquireTokenPopup(…)acquireTokenRedirect(…)In MSAL.js, there are a few functions that obtain tokens: loginPopup(), acquireTokenSilent(...), acquireTokenPopup(…), and acquireTokenRedirect(…).

  • loginPopup() 通过交互式登录请求来获取 ID 令牌,但是无法获取任何服务的访问令牌(包括由条件访问保护的 Web API)。loginPopup() obtains an ID token through an interactive sign-in request but does not obtain access tokens for any service (including a Conditional Access protected web API).
  • 然后可以使用 acquireTokenSilent(…) 以无提示方式获取访问令牌,这意味着在任何情况下它都不会显示 UI。acquireTokenSilent(…) can then be used to silently obtain an access token meaning it does not show UI in any circumstance.
  • acquireTokenPopup(…)acquireTokenRedirect(…) 用于以交互方式请求资源的令牌,这意味着它们始终会显示登录 UI。acquireTokenPopup(…) and acquireTokenRedirect(…) are both used to interactively request a token for a resource meaning they always show sign-in UI.

应用需要访问令牌来调用 Web API 时,它尝试 acquireTokenSilent(…)When an app needs an access token to call a web API, it attempts an acquireTokenSilent(…). 如果令牌会话过期或我们需要符合条件访问策略时,则 acquireToken 函数失败,应用将使用 acquireTokenPopup()acquireTokenRedirect()If the token session is expired or we need to comply with a Conditional Access policy, then the acquireToken function fails and the app uses acquireTokenPopup() or acquireTokenRedirect().

使用 MSAL 流的单页应用示意图

我们来看一个使用条件访问方案的示例。Let's walk through an example with our Conditional Access scenario. 最终用户刚刚登录网站,且没有会话。The end user just landed on the site and doesn’t have a session. 我们执行一个 loginPopup() 调用,未通过多重身份验证获取了 ID 令牌。We perform a loginPopup() call, get an ID token without multi-factor authentication. 然后用户点击一个按钮,要求应用从 Web API 请求数据。Then the user hits a button that requires the app to request data from a web API. 该应用尝试执行一个 acquireTokenSilent() 调用,但是失败,因为用户尚未执行多重身份验证,且需要符合条件访问策略。The app tries to do an acquireTokenSilent() call but fails since the user has not performed multi-factor authentication yet and needs to comply with the Conditional Access policy.

Azure AD 发送回以下 HTTP 响应:Azure AD sends back the following HTTP response:

HTTP 400; Bad Request
error=interaction_required
error_description=AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access '<Web API App/Client ID>'.

应用需要捕获 error=interaction_requiredOur app needs to catch the error=interaction_required. 然后应用程序可以在同一个资源上使用 acquireTokenPopup()acquireTokenRedirect()The application can then use either acquireTokenPopup() or acquireTokenRedirect() on the same resource. 用户被强制执行多重身份验证。The user is forced to do a multi-factor authentication. 用户完成多重身份验证后,应用针对所请求资源签发一个新访问令牌。After the user completes the multi-factor authentication, the app is issued a fresh access token for the requested resource.

若要尝试此应用场景,请参阅 JS SPA 代理代码示例To try out this scenario, see our JS SPA On-behalf-of code sample. 此代码示例使用之前通过 JS SPA 注册的条件访问策略和 Web API 演示此应用场景。This code sample uses the Conditional Access policy and web API you registered earlier with a JS SPA to demonstrate this scenario. 它演示了如何正确处理声明质询并获取可用于 Web API 的访问令牌。It shows how to properly handle the claims challenge and get an access token that can be used for your web API. 或者,请查看常规的 Angular.js 代码示例,获取 Angular SPA 方面的指南。Alternatively, checkout the general Angular.js code sample for guidance on an Angular SPA

另请参阅See also