获取Azure AD Token时发生死锁问题求助
Azure AD Token获取死锁问题解决
你的死锁核心原因是同步方法中强行阻塞等待异步任务完成:getHttpClient里调用taskAccessToken.Result会卡住当前线程,而await pca.AcquireTokenByIntegratedWindowsAuth(...).ExecuteAsync()默认会捕获当前上下文(比如UI线程上下文),异步操作完成后需要回到原线程继续执行,但原线程已经被.Result阻塞,最终形成死锁循环。
解决步骤:
- 全程异步化,避免同步阻塞
把getHttpClient改成异步方法,全程用await等待异步任务,彻底消除.Result导致的阻塞。 - 修复静态变量的线程安全问题
静态变量result在多线程环境下易出现并发访问冲突,建议加锁保护token的刷新逻辑。 - 复用PCA实例
每次获取token都新建PublicClientApplication实例会浪费资源,把实例初始化移到方法外部复用。
修改后的代码示例:
private static AuthenticationResult? _result; private static readonly object _lockObj = new object(); // 复用PCA实例,避免重复创建 private static readonly PublicClientApplication _pca = PublicClientApplicationBuilder .Create("{CLIENTID}") .WithAuthority("https://login.microsoftonline.com/{TENANTID}") .Build(); public static async Task<HttpClient> GetHttpClientAsync() { var httpClient = new HttpClient(); var accessToken = await GetAccessTokenAsync(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); return httpClient; } public static async Task<string> GetAccessTokenAsync() { lock (_lockObj) { // 提前5分钟刷新token,避免刚获取就接近过期 if (_result != null && _result.ExpiresOn - DateTime.UtcNow > TimeSpan.FromMinutes(5)) { return _result.AccessToken; } } var scopes = new[] { "api://{APICLIENTID}/.default" }; Debug.WriteLine("Waiting for Token"); try { var newResult = await _pca.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync(); lock (_lockObj) { _result = newResult; } Debug.WriteLine("Acquired Token"); return newResult.AccessToken; } catch (Exception ex) { MessageBox.Show($"获取Token失败:{ex.Message}"); throw; // 抛出异常让上层处理,避免返回空token导致后续请求失败 } }
关键修改说明:
- 把所有同步方法改为异步方法(命名加
Async后缀符合C#规范) - 用
await替代.Result,彻底消除阻塞导致的死锁 - 加
lock保护静态变量_result的读写,避免多线程同时刷新token - 复用
PublicClientApplication实例,提升性能并减少资源消耗 - 增加提前刷新逻辑,避免token刚获取就进入过期临界期
内容的提问来源于stack exchange,提问作者aron.wissing
相关产品推荐
相关产品推荐

