使用 Microsoft 身份验证库 (MSAL) 获取和缓存令牌

客户端可以使用访问令牌安全调用受 Azure 保护的 Web API。 可以使用 Microsoft 身份验证库 (MSAL) 通过多种方式获取令牌。 某些方式需要用户通过 Web 浏览器进行交互,而另一些方式则不需要用户交互。 通常,用于获取令牌的方法取决于应用程序是公共客户端应用程序(桌面版或移动版),还是机密客户端应用程序(Web 应用、Web API 或守护程序应用)。

MSAL 在获取令牌后会缓存令牌。 在尝试通过其他方式获取令牌之前,应用程序代码应该先尝试以无提示方式从缓存中获取令牌。

你还可以通过从缓存中移除帐户来清除令牌缓存。 不过,这不会删除浏览器中的会话 Cookie。

获取令牌时的范围

范围是客户端应用程序可以请求访问的 Web API 公开的权限。 在发出身份验证请求以获取用于访问 Web API 的令牌时,客户端应用程序将请求用户许可这些范围。 MSAL 允许获取令牌以访问 Microsoft 标识平台 API。 v2.0 协议在请求中使用范围而不是资源。 根据 v2.0 终结点接受的令牌版本的 Web API 配置,该终结点会将访问令牌返回到 MSAL。

MSAL 的一些令牌获取方法需要使用 scopes 参数。 scopes 参数是一个字符串列表,这些字符串声明了所需的权限和所请求的资源。 广为人知的范围是 Microsoft Graph 权限

请求 Web API 的范围

当应用程序需要请求对资源 API 具有特定权限的访问令牌时,请按 <app ID URI>/<scope> 格式传递包含 API 的应用 ID URI 的范围。

适用于不同资源的一些示例范围值:

  • Microsoft Graph API:https://microsoftgraph.chinacloudapi.cn/User.Read
  • 自定义 Web API:api://00001111-aaaa-2222-bbbb-3333cccc4444/api.read

范围值的格式因接收访问令牌的资源 (API) 和其接受的 aud 声明值而异。

单纯对于 Microsoft Graph 而言,user.read 范围映射到 https://microsoftgraph.chinacloudapi.cn/User.Read,这两种范围格式可以互换使用。

某些 Web API(例如 Azure 资源管理器 API (https://management.core.chinacloudapi.cn/))要求在访问令牌的受众声明 (aud) 中使用尾随正斜杠 (/)。 在这种情况下,请将范围作为 https://management.core.chinacloudapi.cn//user_impersonation 传递,其中包括双正斜杠 (//)。

其他 API 可能要求不在范围值中包括方案或主机,并且仅需要应用 ID (GUID) 和范围名称,例如:

00001111-aaaa-2222-bbbb-3333cccc4444/api.read

提示

如果下游资源不受你的控制,而你在将访问令牌传递给资源时收到 401 或其他错误,你可能需要尝试不同的范围值格式(例如,包含/不包含方案和主机)。

当应用程序提供的功能或其要求发生变化时,你可以根据需要使用范围参数请求其他权限。 这样的动态范围允许用户针对范围提供增量许可。

例如,你可以让用户登录,但最初拒绝他们访问任何资源。 然后,你可以在令牌获取方法中请求日历范围并获得用户的同意,从而让用户能够查看其日历。 例如,可以请求 https://microsoftgraph.chinacloudapi.cn/User.Readhttps://microsoftgraph.chinacloudapi.cn/Calendar.Read 范围。

以无提示方式(从缓存中)获取令牌

MSAL 维护一个令牌缓存(对于机密客户端应用程序,则会维护两个),获取令牌后会缓存令牌。 在许多情况下,尝试以无提示方式获取令牌会根据缓存中的令牌获取具有更多范围的另一个令牌。 此外,当某个令牌即将过期时可以刷新该令牌(因为令牌缓存中也包含一个刷新令牌)。

应用程序源代码应该先尝试以无提示方式从缓存中获取令牌。 如果方法调用返回“需要 UI”错误或异常,请尝试通过其他方式获取令牌。

有两个流不支持尝试以无提示方式获取令牌

  • 客户端凭据流:不使用用户令牌缓存,而是使用应用程序令牌缓存。 在将请求发送到安全令牌服务 (STS) 之前,此方法负责验证此应用程序令牌缓存。
  • Web 应用中的授权代码流:因为它兑换应用程序通过将用户登录并让他们许可更多范围而获得的代码。 由于是将代码而不是将帐户作为参数传递,该方法在兑换代码之前无法查看缓存,而兑换代码需要调用服务。

对于使用 OpenID Connect 授权代码流的 Web 应用程序,控制器中的建议模式为:

  • 使用已经过自定义序列化的令牌缓存实例化某个机密客户端应用程序。
  • 使用授权代码流获取令牌

获取令牌

获取令牌的方法取决于应用程序是公共客户端还是机密客户端应用程序。

公共客户端应用程序

在公共客户端应用程序(桌面版和移动版)中,你可以:

  • 让用户通过 UI 或弹出窗口登录,以交互方式获取令牌。
  • 如果桌面应用程序在已加入域或 Azure 的 Windows 计算机上运行,请使用集成 Windows 身份验证 (IWA/Kerberos) 以无提示方式获取已登录用户的令牌。
  • 在 .NET Framework 桌面客户端应用程序中使用用户名和密码获取令牌(不建议这样做)。 在机密客户端应用程序中不要使用用户名/密码。
  • 如果应用程序在没有 Web 浏览器的设备上运行,请通过设备代码流获取令牌。 系统将为用户提供 URL 和代码,然后,他们可以在另一台设备上打开 Web 浏览器、输入代码并登录。 然后,Microsoft Entra ID 会将令牌发回到没有浏览器的设备。

机密客户端应用程序

对于机密客户端应用程序(Web 应用、Web API 或类似于 Windows 服务的守护程序应用),你可以:

  • 使用客户端凭据流获取应用程序本身而不是用户的令牌。 此方法可用于同步工具或者那些处理普通用户而不是特定用户的工具。
  • 使用适用于 Web API 的代表 (OBO) 流以用户身份调用 API。 系统会使用客户端凭据标识应用程序,以根据用户断言(例如 SAML 或 JWT 令牌)获取令牌。 需要在服务到服务调用中访问特定用户的资源的应用程序使用此流。 令牌应按会话而非用户缓存。
  • 在用户通过授权请求 URL 登录后,在 Web 应用中使用授权代码流获取令牌。 OpenID Connect 应用程序通常使用此机制,可让用户使用 OpenID Connect 登录,然后代表用户访问 Web API。 令牌可按用户也可按会话缓存。 如果按用户缓存令牌,建议限制会话生存期,以便 Microsoft Entra ID 频繁检查条件访问策略的状态。

身份验证结果

当客户端请求访问令牌时,Microsoft Entra ID 还会返回一条身份验证结果,其中包含有关访问令牌的元数据。 此信息包含访问令牌的过期时间及其有效范围。 此数据可让应用执行访问令牌的智能缓存,而无需分析访问令牌本身。 身份验证结果公开:

  • 由 Web API 用来访问资源的访问令牌。 此字符串通常是一个 Base64 编码的 JWT,但客户端不得查看访问令牌的内部信息。 不保证格式稳定,并且可以为资源加密令牌。 在客户端上依赖访问令牌内容编写代码是最常见的错误来源之一,并且会违反客户端逻辑。
  • 用户的 ID 令牌 (JWT)。
  • 令牌过期时间,告知令牌的过期日期/时间。
  • 租户 ID 包含用户所在的租户。 对于来宾用户(Microsoft Entra B2B 方案),租户 ID 是来宾租户,而不是唯一的租户。 以用户的名义传送令牌时,身份验证结果还包含有关此用户的信息。 对于未使用用户帐户请求令牌的机密客户端流(适用于应用程序),此用户信息为 null。
  • 令牌的颁发范围。
  • 用户的唯一 ID。

(高级)在后台应用和服务中访问用户的缓存令牌

你可以使用 MSAL 的令牌缓存实现来允许后台应用、API 和服务使用访问令牌缓存,以便在用户不在时代表用户继续执行操作。 如果后台应用和服务需要在用户退出前端 Web 应用后继续代表用户工作,则这样做特别有用。

如今,大多数后台进程都在需要使用用户的数据时使用应用程序权限,而无需用户在场进行身份验证或重新进行身份验证。 由于应用程序权限通常需要管理员同意,这需要特权提升,因此会遇到不必要的摩擦,因为开发人员不打算获得针对其应用的、超出用户最初同意的权限的权限。

GitHub 上的此代码示例演示了如何通过从后台应用访问 MSAL 的令牌缓存来避免这种不必要的摩擦:

从后台应用、API 和服务访问已登录用户的令牌缓存

另请参阅

MSAL 支持的几个平台在该平台库的文档中有其他令牌缓存相关信息。 例如: