使用 Microsoft 身份验证库 (MSAL) 获取和缓存令牌Acquire and cache tokens using the Microsoft Authentication Library (MSAL)

客户端可以使用访问令牌安全调用受 Azure 保护的 Web API。Access tokens enable clients to securely call web APIs protected by Azure. 可以使用 Microsoft 身份验证库 (MSAL) 通过多种方式获取令牌。There are several ways to acquire a token by using the Microsoft Authentication Library (MSAL). 某些方式需要用户通过 Web 浏览器进行交互,而另一些方式则不需要用户交互。Some require user interaction through a web browser, while others don't require user interaction. 一般情况下,用于获取令牌的方式取决于应用程序是公共客户端应用程序(例如桌面或移动应用)还是机密客户端应用程序(例如 Web 应用、Web API 或守护程序应用程序)。In general, the method used for acquiring a token depends on whether the application is a public client application like desktop or mobile app, or a confidential client application like web app, web API, or daemon application.

MSAL 在获取令牌后会缓存令牌。MSAL caches a token after it's been acquired. 在尝试通过其他方式获取令牌之前,应用程序代码应该先尝试以无提示方式从缓存中获取令牌。Your application code should first try to get a token silently from the cache before attempting to acquire a token by other means.

你也可以清除令牌缓存,这可以通过从缓存中删除帐户来实现。You can also clear the token cache, which is achieved by removing the accounts from the cache. 不过,这不会删除浏览器中的会话 Cookie。This doesn't remove the session cookie that's in the browser, however.

获取令牌时的范围Scopes when acquiring tokens

范围是客户端应用程序可以请求访问的 Web API 公开的权限。Scopes are the permissions that a web API exposes that client applications can request access to. 在发出身份验证请求以获取用于访问 Web API 的令牌时,客户端应用程序将请求用户许可这些范围。Client applications request the user's consent for these scopes when making authentication requests to get tokens to access the web APIs. 使用 MSAL 可以获取令牌来访问面向开发人员的 Azure AD (v1.0) 和 Microsoft 标识平台 (v2.0) API。MSAL allows you to get tokens to access Azure AD for developers (v1.0) and Microsoft identity platform (v2.0) APIs. v2.0 协议在请求中使用范围而不是资源。v2.0 protocol uses scopes instead of resource in the requests. 有关详细信息,请阅读 v1.0 与 v2.0 的比较For more information, read v1.0 and v2.0 comparison. 根据 v2.0 终结点接受的令牌版本的 Web API 配置,该终结点会将访问令牌返回到 MSAL。Based on the web API's configuration of the token version it accepts, the v2.0 endpoint returns the access token to MSAL.

MSAL 的一些令牌获取方法需要使用 scopes 参数。Several of MSAL's token acquisition methods require a scopes parameter. scopes 参数是一个字符串列表,这些字符串声明了所需的权限和所请求的资源。The scopes parameter is a list of strings that declare the desired permissions and the resources requested. 广为人知的范围是 Microsoft Graph 权限Well-known scopes are the Microsoft Graph permissions.

在 MSAL 中也可以访问 v1.0 资源。It's also possible in MSAL to access v1.0 resources. 有关详细信息,请参阅 v1.0 应用程序的范围For more information, see Scopes for a v1.0 application.

请求 Web API 的范围Request scopes for a web API

当应用程序需要请求对资源 API 具有特定权限的访问令牌时,请按 <app ID URI>/<scope> 格式传递包含 API 的应用 ID URI 的范围。When your application needs to request an access token with specific permissions for a resource API, pass the scopes containing the app ID URI of the API in the format <app ID URI>/<scope>.

适用于不同资源的一些示例范围值:Some example scope values for different resources:

  • Microsoft Graph API:https://microsoftgraph.chinacloudapi.cn/User.ReadMicrosoft Graph API: https://microsoftgraph.chinacloudapi.cn/User.Read
  • 自定义 Web API:api://11111111-1111-1111-1111-111111111111/api.readCustom web API: api://11111111-1111-1111-1111-111111111111/api.read

范围值的格式因接收访问令牌的资源 (API) 和其接受的 aud 声明值而异。The format of the scope value varies depending on the resource (the API) receiving the access token and the aud claim values it accepts.

单纯对于 Microsoft Graph 而言,user.read 范围映射到 https://microsoftgraph.chinacloudapi.cn/User.Read,这两种范围格式可以互换使用。For Microsoft Graph only, the user.read scope maps to https://microsoftgraph.chinacloudapi.cn/User.Read, and both scope formats can be used interchangeably.

某些 Web API(例如 Azure 资源管理器 API (https://management.core.chinacloudapi.cn/) )要求在访问令牌的受众声明 (aud ) 中使用尾随正斜杠“/”。Certain web APIs such as the Azure Resource Manager API (https://management.core.chinacloudapi.cn/) expect a trailing forward slash ('/') in the audience claim (aud) of the access token. 在这种情况下,请将范围作为 https://management.core.chinacloudapi.cn//user_impersonation 传递,其中包括双正斜杠 ('//')。In this case, pass the scope as https://management.core.chinacloudapi.cn//user_impersonation, including the double forward slash ('//').

其他 API 可能要求不在范围值中包括方案或主机,并且仅需要应用 ID (GUID) 和范围名称,例如:Other APIs might require that no scheme or host is included in the scope value, and expect only the app ID (a GUID) and the scope name, for example:

11111111-1111-1111-1111-111111111111/api.read

提示

如果下游资源不受你的控制,而你在将访问令牌传递给资源时收到 401 或其他错误,你可能需要尝试不同的范围值格式(例如,包含/不包含方案和主机)。If the downstream resource is not under your control, you might need to try different scope value formats (for example with/without scheme and host) if you receive 401 or other errors when passing the access token to the resource.

当应用程序提供的功能或其要求发生变化时,你可以根据需要使用范围参数请求其他权限。As the features provided by your application or its requirements change, you can request additional permissions as needed by using the scope parameter. 这样的动态范围允许用户针对范围提供增量许可。Such dynamic scopes allow your users to provide incremental consent to scopes.

例如,你可以让用户登录,但最初拒绝他们访问任何资源。For example, you might sign in the user but initially deny them access to any resources. 然后,你可以在令牌获取方法中请求日历范围并获得用户的同意,从而让用户能够查看其日历。Later, you can give them the ability to view their calendar by requesting the calendar scope in the acquire token method and obtaining the user's consent to do so. 例如,可以请求 https://microsoftgraph.chinacloudapi.cn/User.Readhttps://microsoftgraph.chinacloudapi.cn/Calendar.Read 范围。For example, by requesting the https://microsoftgraph.chinacloudapi.cn/User.Read and https://microsoftgraph.chinacloudapi.cn/Calendar.Read scopes.

以无提示方式(从缓存中)获取令牌Acquiring tokens silently (from the cache)

MSAL 维护一个令牌缓存(对于机密客户端应用程序,则会维护两个),获取令牌后会缓存令牌。MSAL maintains a token cache (or two caches for confidential client applications) and caches a token after it's been acquired. 在许多情况下,尝试以无提示方式获取令牌会根据缓存中的令牌获取具有更多范围的另一个令牌。In many cases, attempting to silently get a token will acquire another token with more scopes based on a token in the cache. 此外,当某个令牌即将过期时可以刷新该令牌(因为令牌缓存中也包含一个刷新令牌)。It's also capable of refreshing a token when it's getting close to expiration (as the token cache also contains a refresh token).

应用程序代码应该先尝试以无提示方式从缓存中获取令牌。Application code should first try to get a token silently from the cache. 如果方法调用返回“需要 UI”错误或异常,请尝试通过其他方式获取令牌。If the method call returns a "UI required" error or exception, try acquiring a token by other means.

但是,在下面的两个流中,不应尝试以无提示方式获取令牌:There are two flows, however, in which you should not attempt to silently acquire a token:

  • 客户端凭据流:不使用用户令牌缓存,而是使用应用程序令牌缓存。Client credentials flow, which does not use the user token cache but an application token cache. 在将请求发送到安全令牌服务 (STS) 之前,此方法负责验证此应用程序令牌缓存。This method takes care of verifying the application token cache before sending a request to the security token service (STS).
  • Web 应用中的授权代码流:因为它兑换应用程序通过将用户登录并让他们许可更多范围而获得的代码。Authorization code flow in web apps, as it redeems a code that the application obtained by signing in the user and having them consent to more scopes. 由于是将代码而不是将帐户作为参数传递,该方法在兑换代码之前无法查看缓存,而兑换代码需要调用服务。Since a code and not an account is passed as a parameter, the method can't look in the cache before redeeming the code, which invokes a call to the service.

对于使用 OpenID Connect 授权代码流的 Web 应用程序,控制器中的建议模式为:For Web applications that use the OpenID Connect authorization code flow, the recommended pattern in the controllers is to:

  • 使用已经过自定义序列化的令牌缓存实例化某个机密客户端应用程序。Instantiate a confidential client application with a token cache with customized serialization.
  • 使用授权代码流获取令牌Acquire the token using the authorization code flow

获取令牌Acquiring tokens

一般情况下,获取令牌的方法取决于应用程序是公共客户端还是机密客户端应用程序。Generally, the method of acquiring a token depends on whether it's a public client or confidential client application.

公共客户端应用程序Public client applications

对于公共客户端应用程序(桌面或移动应用):For public client applications (desktop or mobile app), you:

  • 通常是让用户通过 UI 或弹出窗口登录,以交互方式获取令牌。Often acquire tokens interactively, having the user sign in through a UI or pop-up window.
  • 如果桌面应用程序在已加入域或 Azure 的 Windows 计算机上运行,则可以使用 Windows 集成身份验证 (IWA/Kerberos) 以无提示方式获取已登录用户的令牌Can get a token silently for the signed-in user using Integrated Windows Authentication (IWA/Kerberos) if the desktop application is running on a Windows computer joined to a domain or to Azure.
  • 可以在 .NET Framework 桌面客户端应用程序中使用用户名和密码获取令牌(不建议这样做)。Can get a token with a username and password in .NET framework desktop client applications (not recommended). 在机密客户端应用程序中不要使用用户名/密码。Do not use username/password in confidential client applications.
  • 如果应用程序在没有 Web 浏览器的设备上运行,则可在应用程序中通过设备代码流获取令牌。Can acquire a token through the device code flow in applications running on devices that don't have a web browser. 系统将为用户提供 URL 和代码,然后,他们可以在另一台设备上打开 Web 浏览器、输入代码并登录。The user is provided with a URL and a code, who then goes to a web browser on another device and enters the code and signs in. 然后,Azure AD 会将令牌发回到没有浏览器的设备。Azure AD then sends a token back to the browser-less device.

机密客户端应用程序Confidential client applications

对于机密客户端应用程序(Web 应用、Web API 或类似于 Windows 服务的守护程序应用程序),请执行以下操作:For confidential client applications (web app, web API, or a daemon application like a Windows service), you:

  • 使用客户端凭据流获取应用程序本身而不是用户的令牌。Acquire tokens for the application itself and not for a user, using the client credentials flow. 此方法可用于同步工具或者那些处理普通用户而不是特定用户的工具。This technique can be used for syncing tools, or tools that process users in general and not a specific user.
  • 使用适用于 Web API 的代表流代表用户调用 API。Use the on-behalf-of flow for a web API to call an API on behalf of the user. 系统会使用客户端凭据标识应用程序,以根据用户断言(例如 SAML 或 JWT 令牌)获取令牌。The application is identified with client credentials in order to acquire a token based on a user assertion (SAML, for example, or a JWT token). 需要在服务到服务调用中访问特定用户的资源的应用程序使用此流。This flow is used by applications that need to access resources of a particular user in service-to-service calls.
  • 在用户通过授权请求 URL 登录后,在 Web 应用中使用授权代码流获取令牌。Acquire tokens using the authorization code flow in web apps after the user signs in through the authorization request URL. OpenID Connect 应用程序通常使用此机制,可让用户使用 Open ID Connect 登录,然后代表用户访问 Web API。OpenID Connect application typically use this mechanism, which lets the user sign in using Open ID connect and then access web APIs on behalf of the user.

身份验证结果Authentication results

当客户端请求访问令牌时,Azure AD 还会返回一条身份验证结果,其中包含有关访问令牌的元数据。When your client requests an access token, Azure AD also returns an authentication result that includes metadata about the access token. 此信息包含访问令牌的过期时间及其有效范围。This information includes the expiry time of the access token and the scopes for which it's valid. 此数据可让应用执行访问令牌的智能缓存,而无需分析访问令牌本身。This data allows your app to do intelligent caching of access tokens without having to parse the access token itself. 身份验证结果公开:The authentication result exposes:

  • 由 Web API 用来访问资源的访问令牌The access token for the web API to access resources. 此字符串通常是一个 Base64 编码的 JWT,但客户端不得查看访问令牌的内部信息。This string is usually a Base64-encoded JWT, but the client should never look inside the access token. 不保证格式稳定,并且可以为资源加密令牌。The format isn't guaranteed to remain stable, and it can be encrypted for the resource. 在客户端上依赖访问令牌内容编写代码是最常见的错误来源之一,并且会违反客户端逻辑。People writing code depending on access token content on the client is one of the most common sources of errors and client logic breakage.
  • 用户的 ID 令牌 (JWT)。The ID token for the user (a JWT).
  • 令牌过期时间,告知令牌的过期日期/时间。The token expiration, which tells the date/time when the token expires.
  • 租户 ID 包含用户所在的租户。The tenant ID contains the tenant in which the user was found. 对于来宾用户(Azure AD B2B 方案),租户 ID 是来宾租户,而不是唯一的租户。For guest users (Azure AD B2B scenarios), the tenant ID is the guest tenant, not the unique tenant. 以用户的名义传送令牌时,身份验证结果还包含有关此用户的信息。When the token is delivered in the name of a user, the authentication result also contains information about this user. 对于未使用用户帐户请求令牌的机密客户端流(适用于应用程序),此用户信息为 null。For confidential client flows where tokens are requested with no user (for the application), this user information is null.
  • 令牌的颁发范围。The scopes for which the token was issued.
  • 用户的唯一 ID。The unique ID for the user.

后续步骤Next steps

如果使用的是适用于 Java 的 MSAL,请了解适用于 Java 的 MSAL 中的自定义令牌缓存序列化If you're using MSAL for Java, learn about custom token cache serialization in MSAL for Java.

了解如何处理错误和异常Learn about handling errors and exceptions.