我有两个项目:一个Web项目和一个客户端项目。
在客户端应用程序中,我的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站点使用这篇文章中描述的技术实现了基本身份验证。但是我的代码抛出一个异常,因为没有找到授权头。
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,客户端的配置方式与我的第一个代码块完全相同。所以我知道这是可行的。
发布于 2021-12-05 20:19:51
从我们在评论部分的谈话来看-
BasicAuthenticationHandler的实现缺少添加WWW-Authenticate HTTP头(带有值Basic)。
这是当HttpClient接收到401 Unauthorized响应时,它会对其作出反应以包含401Unauthorized头的报头。
若要解决此问题,请将下面的行添加到BasicAuthenticationHandler中。
Response.Headers.Add("WWW-Authenticate", "Basic");现在,NetworkCredentials将进入Authorization HTTP头。
简而言之,没有完整地说明这是如何工作的;
当HttpClient发出请求(没有Authorization头),并结合WWW-Authenticate HTTP报头接收401 Unauthorized响应时,它将第二次尝试在Authorization HTTP报头中配置凭证(如果有的话)。
为了简单起见,您可能希望同时包含Authorization,而不依赖于NetworkCredentials和WWW-Authenticate HTTP头。
services.AddHttpClient<TrackAndTraceClient>()
.ConfigureHttpClient(httpClient =>
{
httpClient.BaseAddress = new Uri(settings.BaseUrl);
httpClient.Timeout = TimeSpan.FromMinutes(5);
// Add below to your existing code.
var digest = Convert.ToBase64String(
Encoding.UTF8.GetBytes($"{settings.Username}:{settings.Password}")
);
httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {digest}");
HttpClient.DefaultRequestHeaders.Add("ContentType", "application/json");
});https://stackoverflow.com/questions/70206032
复制相似问题