【发布时间】:2022-01-09 07:59:31
【问题描述】:
我有两个项目:一个 Web API 项目和一个客户端项目。
在客户端应用程序中,我像这样配置我的HttpClient。
services.AddHttpClient<TrackAndTraceClient>()
.ConfigureHttpClient(httpClient =>
{
httpClient.BaseAddress = new Uri(settings.BaseUrl);
httpClient.Timeout = TimeSpan.FromMinutes(5);
})
.ConfigurePrimaryHttpMessageHandler(serviceProvider =>
{
return new HttpClientHandler()
{
Credentials = new NetworkCredential(settings.Username, settings.Password),
};
});
然后在我的调用 API 的类中:
public TrackAndTraceClient(IHttpClientFactory httpClientFactory, IOptions<TrackAndTraceSettings> settings)
{
HttpClient = httpClientFactory.CreateClient(nameof(TrackAndTraceClient));
Settings = settings.Value;
}
我的 Web API 站点使用this article 中描述的技术实现基本身份验证。但是我的代码抛出异常,因为没有找到 Authorization 标头。
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// ...
if (!Request.Headers.TryGetValue("Authorization", out StringValues authHeaderValues))
throw new Exception("Missing Authorization header");
// ...
}
}
我只能通过将以下代码添加到调用 API 的类中来使其工作:
HttpClient.DefaultRequestHeaders.Add("ContentType", "application/json");
byte[] credentialsData = Encoding.UTF8.GetBytes($"{Settings.Username}:{Settings.Password}");
string credentials = Convert.ToBase64String(credentialsData);
HttpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {credentials}");
谁能告诉我为什么需要最后一段代码?为什么使用NetworkCredential 设置凭据似乎没有任何作用?以及如何更改我的 Web API 以使其使用原始方式指定的凭据?
请注意,我还调用了第三方 API,并且客户端的配置方式与我的第一个代码块中的完全相同。所以我知道这可以发挥作用。
【问题讨论】:
-
如果不查看对第三方系统和您的服务器的实际 HTTP 请求和响应,就很难判断。例如,您的 WebAPI 是否返回 HTTP 401 Unauthorized with WWW-Authenticate: Basic header?除非得到指示,否则我不希望 HttpClientHandler 参与授权过程。
-
@ZdeněkJelínek:我正在检查我的基本身份验证处理程序中的标头(请参阅this article)。所以 Web API 会返回我指出的任何内容。
-
这里是凭记忆走的,请耐心等待。您正在创建一个类型化的
HttpClient(.AddHttpClient<>()),而不是命名的HttpClient(.AddHttpClient(string))...所以当您注入IHttpClientFactory并运行.CreateClient(string)时,它不会找到您的客户端设置。使用类型化客户端,您根本不需要使用IHttpClientFactory,而只需直接注入HttpClient。 -
@GTHvidsten:是的,看起来你可能对不需要
IHttpClientFactory进行依赖注入是正确的。我目前正在对此进行审查。但是,除了授权标头之外,我的代码仍然获得由我的代码配置的HttpClient实例。所以这个建议似乎与我遇到的问题无关。 -
@pfx:天哪!你说的对!我有点困惑,因为我认为 401 响应是由我的代码返回
AuthenticateResult.Fail("Access Denied")触发的。但实际上,添加该响应标头,现在它可以工作了。我不太明白,但你似乎解决了这个问题。随意写出来作为答案,我会接受的。
标签: c# asp.net authentication asp.net-web-api .net-6.0