問題描述
Web App 調用 Azure Entra ID 中國區認證端點 login.chinacloudapi.cn 獲取訪問令牌時,產生了異常巨大的 Entra ID 請求量,最終導致請求失敗和整體登錄不穩定。
問題發生在使用 MSAL 的 AcquireTokenForClient 獲取 Token 場景中,表面現象是“Web App 調用 Entra ID 失敗”,實質原因則與令牌緩存未生效密切相關。
問題解答
Web App 使用的是 Client Credentials Flow(客户端憑據模式),核心實現依賴 MSAL 的 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
當在複雜的環境中面臨問題,格物之道需:濁而靜之徐清,安以動之徐生。 雲中,恰是如此!