启用Azure AD(M365)认证后Blazor Server控制器无法被调用
启用Azure AD(M365)认证后Blazor Server控制器无法被调用
看起来你遇到的核心问题是:启用Azure AD认证后,你的API端点需要经过身份验证才能访问,但你当前的CustomHttpClient没有携带有效的访问令牌,所以请求被自动重定向到Microsoft的登录页面,根本没机会进入你的控制器逻辑。我来一步步帮你解决这个问题:
1. 先确认Program.cs的认证配置是否完整
首先,你需要在Program.cs里配置Microsoft Identity Web时,同时启用获取下游API令牌的能力——因为你的Blazor Server应用现在既是客户端(登录用户),又要调用自己的API(下游资源)。示例配置如下:
var builder = WebApplication.CreateBuilder(args); // 配置Azure AD认证,同时启用令牌获取能力 builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd") // 这里传入的scope要和你appsettings.json里的Scope一致,还要确保Azure AD里已配置对应权限 .EnableTokenAcquisitionToCallDownstreamApi(new[] { builder.Configuration["AzureAd:Scope"] }) .AddInMemoryTokenCaches(); // 添加API控制器支持 builder.Services.AddControllersWithViews(); // Blazor Server相关服务,记得添加 consent handler builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor() .AddMicrosoftIdentityConsentHandler(); // 推荐用HttpClient工厂来管理HttpClient,避免手动创建的资源浪费 builder.Services.AddHttpClient(); var app = builder.Build(); // 中间件顺序很重要,认证要在授权之前 app.UseAuthentication(); app.UseAuthorization(); // 映射控制器路由 app.MapControllers(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.Run();
2. 重写你的HttpClient服务,带上访问令牌
你之前手动创建HttpClient的方式不仅资源管理不规范,更关键的是没添加认证令牌。我们改成注入服务的方式,用ITokenAcquisition获取当前用户的访问令牌,再添加到请求头里:
public class CustomHttpClientService { private readonly IHttpClientFactory _httpClientFactory; private readonly ITokenAcquisition _tokenAcquisition; private readonly IConfiguration _configuration; // 通过构造函数注入所需服务 public CustomHttpClientService(IHttpClientFactory httpClientFactory, ITokenAcquisition tokenAcquisition, IConfiguration configuration) { _httpClientFactory = httpClientFactory; _tokenAcquisition = tokenAcquisition; _configuration = configuration; } public async Task<T> GetJsonAsync<T>(string requestUri) { var httpClient = _httpClientFactory.CreateClient(); var apiScope = _configuration["AzureAd:Scope"]; try { // 获取当前用户访问API的令牌 var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { apiScope }); // 把令牌添加到Authorization请求头 httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); } catch (Exception ex) { // 这里可以处理令牌获取失败的情况,比如重定向到登录页 throw; } var httpResponse = await httpClient.GetAsync(requestUri); // 确保请求成功,否则抛出异常便于调试 httpResponse.EnsureSuccessStatusCode(); var jsonContent = await httpResponse.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject<T>(jsonContent); } }
然后别忘了在Program.cs里注册这个服务:
builder.Services.AddScoped<CustomHttpClientService>();
3. 给控制器加上[Authorize]属性
虽然启用认证后可能默认保护API,但显式添加[Authorize]属性更清晰,确保只有经过身份验证的用户才能访问:
[Route("api/[controller]")] [ApiController] [Authorize] // 新增这个属性 public class Task_ManagementController : ControllerBase { private readonly SqlDbContext _dbContext; public Task_ManagementController(SqlDbContext dbContext) { _dbContext = dbContext; } [HttpGet] [Route("Get")] public async Task<List<Task_Management>> Get() { return await _dbContext.Task_Management.ToListAsync(); } }
4. 检查Azure AD的后台配置
最后要确认Azure AD里的权限配置是否正确:
- 你的Blazor Server客户端应用,必须已经添加了对目标API(就是你自己的控制器对应的API)的权限,并且已经授予管理员同意。
- appsettings.json里的
Scope格式要正确,应该是api://{你的API的ClientId}/{权限名称},比如api://sample/access_as_user;如果你的API没自定义权限,也可以用默认的user_impersonation权限。
另外提个小建议:开发环境里跳过证书验证(就是你之前的clientHandler.ServerCertificateCustomValidationCallback)可以临时用,但正式环境一定要删掉,不然会有安全风险。
备注:内容来源于stack exchange,提问作者ComfortableOnion
相关产品推荐
相关产品推荐

