问题描述
Web App 调用 Azure Entra ID 中国区认证端点 login.chinacloudapi.cn 获取访问令牌时,产生了异常巨大的 Entra ID 请求量,最终导致请求失败和整体登录不稳定。
问题发生在使用 MSAL 的 AcquireTokenForClient 获取 Token 场景中,表面现象是“Web App 调用 Entra ID 失败”,实质原因则与令牌缓存未生效密切相关。
问题解答
ConfidentialClientApplication 与 AcquireTokenForClient 方法。var app = ConfidentialClientApplicationBuilder.Create(clientId).WithClientSecret(clientSecret).WithAuthority(new Uri(authority)) .WithLegacyCacheCompatibility(false).WithCacheOptions(CacheOptions.EnableSharedCacheOptions).Build();
以及在获取访问令牌时:
await app.AcquireTokenForClient(scopes).ExecuteAsync();
围绕上述代码,AcquireTokenForClient 获取 Token 的完整流程可以拆解为以下几个关键点:
一:ConfidentialClientApplication 是 Token 缓存的承载者
ConfidentialClientApplication 表示 Web App 自身在 Azure Entra ID中的“应用身份”,它不仅负责向 Entra ID发起认证请求,同时内部维护了 MSAL 的访问令牌缓存。如果该对象被频繁创建或生命周期过短,缓存将无法复用,直接导致每次获取 token 都访问 Entra ID。
二:WithCacheOptions(CacheOptions.EnableSharedCacheOptions) 的核心作用
.WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
这行代码的意义在于:
- 显式启用 Shared Token Cache
- 允许同一应用实例在多个 token 请求之间共享并复用已获取的 access token
- 在 token 有效期内,MSAL 会优先从缓存返回 token,而不是访问 Entra ID
缺少该配置,或未正确复用 app 对象时,即使使用了 MSAL,也相当于每次 AcquireTokenForClient 都是一次全新的登录请求。
三:AcquireTokenForClient 的真实执行逻辑
当调用以下代码时:
await app.AcquireTokenForClient(scopes).ExecuteAsync();
MSAL 实际执行顺序为:
1:在本地缓存中查找匹配 scopes 的 access token
2:如果 token 存在且未过期 → 直接返回(不调用 AAD (Entra ID))
3:如果不存在或已过期 → 才向 login.chinacloudapi.cn 发起一次新的 token 请求
4:将新 token 写入缓存,供后续请求复用
- 应用级别(如 Startup / Singleton)创建一次
ConfidentialClientApplication 启用.WithCacheOptions(CacheOptions.EnableSharedCacheOptions)- 所有业务代码统一调用
AcquireTokenForClient获取 token
通过该方式,可以显著降低对 Azure Entra ID的请求压力,避免登录风暴,并提升 Web App 的稳定性。
参考资料
MSAL Token Cache 说明 :https://learn.microsoft.com/en-us/entra/identity-platform/msal-acquire-cache-tokens#acquiring-tokens