Blazor WebAssembly独立应用获取多AAD保护API令牌及调用疑问
解决Blazor WASM MSAL多范围令牌获取问题
我明白你遇到的困扰——Angular里MSAL能自动搞定多API的令牌获取和请求拦截,但Blazor WASM的MSAL配置确实需要更明确的设置才能支持多个不同AD App API的令牌获取。下面是具体的解决方案:
核心原因
Blazor的AddMsalAuthentication默认只为单个API(即你配置的ClientId对应的API)处理令牌获取,当你添加多个跨不同AD App的范围时,它不会自动为每个API单独请求令牌。要实现类似Angular的自动拦截匹配,需要为每个API单独配置HttpClient并绑定对应的范围。
方案1:配置命名HttpClient(推荐,类似Angular自动拦截)
通过IHttpClientFactory为每个API创建命名的HttpClient实例,每个实例绑定对应的授权范围和API地址,这样发送请求时会自动获取并附加正确的令牌。
配置代码
在Program.cs中添加以下配置(替换你的API地址和范围):
builder.Services.AddMsalAuthentication(options => { var config = options.ProviderOptions; config.Authentication.Authority = "https://login.microsoftonline.com/tenantID"; config.Authentication.ClientId = "clientID"; options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access"); }); // 配置Graph API的专属HttpClient builder.Services.AddHttpClient("GraphAPI", client => { client.BaseAddress = new Uri("https://graph.microsoft.com/"); }) .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>() .AddHttpMessageHandler(sp => { var handler = sp.GetRequiredService<BaseAddressAuthorizationMessageHandler>() .ConfigureHandler( authorizedUrls: new[] { "https://graph.microsoft.com/" }, scopes: new[] { "https://graph.microsoft.com/user.read" }); return handler; }); // 配置Dynamics CRM的专属HttpClient builder.Services.AddHttpClient("DynamicsCRM", client => { client.BaseAddress = new Uri("https://tenant.crm.dynamics.com/"); }) .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>() .AddHttpMessageHandler(sp => { var handler = sp.GetRequiredService<BaseAddressAuthorizationMessageHandler>() .ConfigureHandler( authorizedUrls: new[] { "https://tenant.crm.dynamics.com/" }, scopes: new[] { "https://tenant.crm.dynamics.com/user_impersonation" }); return handler; }); // 配置自定义API的专属HttpClient builder.Services.AddHttpClient("CustomAPI", client => { client.BaseAddress = new Uri("https://your-custom-api-url/"); }) .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>() .AddHttpMessageHandler(sp => { var handler = sp.GetRequiredService<BaseAddressAuthorizationMessageHandler>() .ConfigureHandler( authorizedUrls: new[] { "https://your-custom-api-url/" }, scopes: new[] { "clientID/scope1" }); return handler; });
在页面中使用
注入IHttpClientFactory,创建对应命名的HttpClient即可自动携带正确令牌:
@inject IHttpClientFactory HttpClientFactory <button @onclick="FetchGraphData">获取Graph用户数据</button> <button @onclick="FetchCrmData">获取Dynamics CRM账户数据</button> @code { private async Task FetchGraphData() { var graphClient = HttpClientFactory.CreateClient("GraphAPI"); var userData = await graphClient.GetFromJsonAsync<dynamic>("me"); // 处理数据 } private async Task FetchCrmData() { var crmClient = HttpClientFactory.CreateClient("DynamicsCRM"); var accounts = await crmClient.GetFromJsonAsync<dynamic>("/api/data/v9.2/accounts"); // 处理数据 } }
方案2:手动获取令牌(灵活场景)
如果需要更灵活的控制(比如动态切换范围),可以使用IAccessTokenAcquisition服务手动获取指定范围的令牌,然后附加到请求头中:
@inject HttpClient HttpClient @inject IAccessTokenAcquisition TokenAcquisition <button @onclick="FetchCrmDataManual">手动获取令牌请求CRM</button> @code { private async Task FetchCrmDataManual() { // 获取Dynamics CRM的令牌 var crmToken = await TokenAcquisition.GetAccessTokenForUserAsync( new[] { "https://tenant.crm.dynamics.com/user_impersonation" }); // 创建请求并添加授权头 var request = new HttpRequestMessage( HttpMethod.Get, "https://tenant.crm.dynamics.com/api/data/v9.2/accounts"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", crmToken); var response = await HttpClient.SendAsync(request); response.EnsureSuccessStatusCode(); var accounts = await response.Content.ReadFromJsonAsync<dynamic>(); // 处理数据 } }
注意事项
- 确保每个AD App的API都已在Azure AD中配置了正确的范围,且Blazor客户端ID已获得对应的权限(管理员同意或用户同意)。
offline_access范围不需要单独绑定到HttpClient,它是用于刷新令牌的,配置在DefaultAccessTokenScopes中即可。
内容的提问来源于stack exchange,提问作者Circus Ranger
相关产品推荐
相关产品推荐

