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

ASP.NET Core Web API通过HttpClient调用同服务器API遇Windows认证401错误

问题描述

两台运行在同一服务器上的ASP.NET Core 7.0 Web API服务,均启用Windows认证并使用不同的AD服务账户运行。本地开发环境中,通过HttpClient从第一个服务调用第二个服务时,Windows身份可正常传递并通过授权;但部署到服务器后,该调用出现HTTP 401未授权错误。

相关代码与日志信息:

受影响的控制器代码

[Authorize]
[ApiController]
[Route("[controller]")]    
public class WeatherController : Controller
{

服务配置(Program.cs)

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
                 .AddNegotiate();

builder.Services.AddAuthorization(options =>
        {
            // 默认所有请求遵循默认授权策略
            options.FallbackPolicy = options.DefaultPolicy;
        });
builder.Services.AddHttpContextAccessor();

var app = builder.Build();

HttpClient调用代码

using (HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
{
    HttpResponseMessage response = client.GetAsync(apiUrl + "Weather/GetWeather").Result;

    if (response.IsSuccessStatusCode)
    {
        weatherResults = JsonConvert.DeserializeObject<List<Weather>>(response.Content.ReadAsStringAsync().Result);
    }
    else
    {                   
        throw new InvalidOperationException($"failed: {response.StatusCode}");
    }
}

IIS日志对比

2023-08-04 21:53:44 xxx.xx.x.xxx GET /Weather/GetWeather/5afd17a9-5845-4e23-82e1-153a1927d047/2022-01-01T00:00:00/2023-08-04T17:53:24 - 443 - xxx.xx.x.xxx - - 401 2 5 0

2023-08-04 21:53:45 xxx.xx.x.xxx GET /Weather/GetWeather/5afd17a9-5845-4e23-82e1-153a1927d047/2022-01-01T00:00:00/2023-08-04T17:53:24 - 443 Domain\User xxx.xx.x.xxx - - 200 0 0 1427

本地开发时VS以个人账户运行,部署后服务以AD账户运行,需排查身份传递失败的原因。


解决建议

1. 配置Kerberos约束委派

当服务以AD账户运行并需要传递身份到另一服务时,Kerberos约束委派是核心解决方向:

  • 在AD用户和计算机管理中,找到运行第一个API的AD服务账户
  • 打开属性→委派标签,选择「信任此用户用于委派到指定服务」
  • 添加第二个API服务对应的SPN(服务主体名称),格式通常为 HTTP/<目标API的主机名> 和 HTTP/<目标API的FQDN>
  • 用setspn -L <账户名>命令验证第二个API的AD服务账户是否已注册对应SPN,未注册则用setspn -A HTTP/your-server-name DOMAIN\ServiceAccount2命令添加

2. 检查IIS认证配置

  • 确保两台API所在的IIS站点均启用Windows认证,禁用匿名认证
  • 进入IIS站点的「认证」→「Windows认证」→「高级设置」,勾选「启用内核模式认证」
  • 确认站点应用程序池的运行身份为对应的AD服务账户,且该账户拥有站点目录的读写权限

3. 优化HttpClient的使用方式

  • 避免直接创建HttpClient实例,改用依赖注入注册:
    // Program.cs中注册HttpClient
    builder.Services.AddHttpClient("SecondApiClient", client =>
    {
        client.BaseAddress = new Uri(apiUrl);
    }).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
    {
        UseDefaultCredentials = true,
        PreAuthenticate = true // 提前发送认证信息,减少协商次数
    });
    
    在调用类中注入IHttpClientFactory并使用异步调用:
    private readonly IHttpClientFactory _httpClientFactory;
    
    public YourService(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }
    
    public async Task<List<Weather>> GetWeather()
    {
        var client = _httpClientFactory.CreateClient("SecondApiClient");
        var response = await client.GetAsync("Weather/GetWeather");
        response.EnsureSuccessStatusCode();
        return await JsonConvert.DeserializeObjectAsync<List<Weather>>(await response.Content.ReadAsStringAsync());
    }
    
  • 替换同步调用(.Result)为异步调用,避免线程上下文丢失导致身份传递失败

4. 验证NTLM策略设置

若Kerberos配置暂时无法生效,可临时检查NTLM限制:

  • 打开「本地组策略编辑器」→「计算机配置」→「Windows设置」→「安全设置」→「本地策略」→「安全选项」
  • 确认「网络安全:LAN管理器身份验证级别」设置为「发送NTLMv2响应\拒绝LM & NTLM」或更宽松级别(仅用于测试,优先使用Kerberos)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 06:31:15