You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8中HealthChecks.UI调用/health报Unauthorized问题排查

问题描述

原始问题

基于.NET 8.0构建的项目,使用Azure AD(Entra ID)做身份验证,站点需登录关联AAD的微软账号并具备对应权限,其他功能及/health端点权限均正常,但遇到以下异常:

  • website.com/health:可正常返回健康状态JSON,内容如下:
    {"status":"Healthy","totalDuration":"00:00:01.1584121","entries":{"sqlserver":{"data":{},"duration":"00:00:01.1117668","status":"Healthy","tags":[]}}}
    
  • website.com/healthchecks-ui:界面能正常加载,但健康检查显示“unhealthy”,错误信息为:
    HTTP response is not in valid state (Unauthorized) when trying to get report from /health configured with name All Health Checks.

相关配置代码

服务注册

services.AddHealthChecks().AddSqlServer(Configuration.GetConnectionString("OpkCoreDatabaseProduction")); 
services.AddHealthChecksUI().AddInMemoryStorage();

端点注册

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "areas",
        pattern: "{area}/{controller}/{action=Index}/{id?}");
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{area=General}/{controller=Home}/{action=Index}/{id?}");
    endpoints.MapGraphQL("/graphql");
    endpoints.MapHealthChecks("/health", new HealthCheckOptions
    {
        ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
    }).AllowAnonymous();
    endpoints.MapHealthChecksUI().AllowAnonymous();
});

appsettings.json配置

"HealthChecksUI": { 
  "HealthChecks": [ 
    { 
      "Name": "All Health Checks", 
      "Uri": "/health" 
    } 
  ], 
  "EvaluationTimeInSeconds": 5 
}

身份验证配置

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));

已尝试的方案:

  • 调整多种AddAuthorization()和AllowAnonymous()配置,/health始终正常,但HealthChecks.UI授权失败
  • 服务器调试无法复现本地情况,也无法调试问题类库
  • 修改Uri为完整域名,无效
  • 不想设置IIS允许匿名访问整个站点

疑问:是否遗漏了令牌请求头的配置环节?

更新内容

确认存在深层次身份验证问题,且与HealthChecks.UI项目无关:
搭建了简单测试控制器,本地运行可正常返回数据,但在QA服务器调试时,调用https://mywebsite.com/health明确返回Unauthorized。测试控制器代码:

public async Task<IActionResult> Index()
{
    HealthCheckViewModel model = new();

    using HttpClient client = new();
    HttpResponseMessage response = await client.GetAsync($"https://mywebsite.com/health");
    var testResponse = response.Content.ReadAsStringAsync().Result;

    return View(model);
}

解决方案

1. 排查服务器端/health端点的匿名访问拦截

虽然代码中给/health添加了.AllowAnonymous(),但QA服务器可能存在额外的身份验证拦截:

  • 检查IIS站点的身份验证设置:确保匿名身份验证已启用,同时禁用其他强制身份验证的模块(如Windows身份验证)
  • 若使用反向代理(如Azure应用网关、NGINX),验证代理是否未额外添加规则拦截/health请求

2. 配置HealthChecks.UI内部请求的身份凭证

HealthChecks.UI的后台收集器是服务器内部发起的请求,部署环境中可能缺少身份令牌导致拦截,可通过添加授权头解决:

services.AddHealthChecksUI(settings =>
{
    settings.AddHealthCheckEndpoint("All Health Checks", "/health")
            .WithHeader("Authorization", $"Bearer {GetAadClientCredentialToken()}");
}).AddInMemoryStorage();

GetAadClientCredentialToken()需实现基于AAD客户端凭据流获取令牌的逻辑(可借助Microsoft.Identity.Client库)

3. 验证服务器环回请求权限

QA服务器可能限制了本地回环请求:

  • 检查防火墙设置,允许127.0.0.1、localhost的HTTP/HTTPS请求
  • 若用HTTPS,确保服务器证书能被本地请求信任,避免SSL验证失败

4. 明确端点的匿名授权规则

调整/health的授权配置,确保匿名访问规则生效:

endpoints.MapHealthChecks("/health", new HealthCheckOptions
{
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
}).RequireAuthorization(new AuthorizeAttribute { AllowAnonymous = true });

内容的提问来源于stack exchange,提问作者Glen Eccles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:33:27