访问服务器上的 HttpClientHandler.Credentials?

Posted

技术标签:

【中文标题】访问服务器上的 HttpClientHandler.Credentials?【英文标题】:Accessing HttpClientHandler.Credentials on the server? 【发布时间】:2021-11-25 19:56:05 【问题描述】:

我正在尝试在 Web API 服务器和调用 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),
        ;
    );

但是,这会导致服务器端没有收到 Authorization 标头。

我的问题是,以这种方式设置凭据实际上有什么作用?这些凭据放在哪里?

是否可以编写我的服务器以处理以这种方式配置的凭据?

【问题讨论】:

【参考方案1】:

您可以将 Authorization 标头添加到您的客户端代码中,如下所示:

services.AddHttpClient<TrackAndTraceClient>()
     .ConfigureHttpClient(httpClient =>
     
         httpClient.BaseAddress = new Uri(settings.BaseUrl);
         httpClient.Timeout = TimeSpan.FromMinutes(5);
         var authenticationBytes = Encoding.ASCII.GetBytes($"settings.Username:settings.Password");
         httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authenticationBytes));
     );

您可以使用AuthenticationHandler 来检查服务器端的Authorization 标头。下面是example 介绍如何使用 AuthenticationHandler 实现基本身份验证。

【讨论】:

我已经有了执行此操作的代码。我的问题是 1. 当我设置 Credentials 属性时凭据放置在哪里,以及 2. 如何配置服务器以读取设置的凭据。【参考方案2】:

PreAuthenticate 应该发送身份验证标头。

services.AddHttpClient<TrackAndTraceClient>()
 .ConfigureHttpClient(httpClient =>
 
    httpClient.BaseAddress = new Uri(settings.BaseUrl);
    httpClient.Timeout = TimeSpan.FromMinutes(5);
 )
 .ConfigurePrimaryHttpMessageHandler(serviceProvider =>
 
    return new HttpClientHandler()
    
      PreAuthenticate = true,
      Credentials = new NetworkCredential(settings.Username, 
       settings.Password)
    ;
 );

如果这不起作用,可能是由于HttpClientHandler 类中的Credentials 属性具有[UnsupportedOSPlatform("browser")] 属性(从.NET 5 开始)——注意PreAuthenticate 属性也是如此。此外,HttpClientHandler 类还包含如下定义:

.NET Framework 和 .NET Core 2.0 及更早版本中 HttpClient 使用的默认消息处理程序。

我看到你的帖子有标签.NET 6,所以这也可能是导致它没有发送的一个因素。如果我是你,我会使用中间件从请求中接收身份验证标头,并使用 @Burhan Savci 发布的解决方案发送它。

假设您的后端是类似的 .NET Core API:

public class BasicAuthMiddleware

    private readonly RequestDelegate _next;

    public BasicAuthMiddleware(RequestDelegate next)
    
       _next = next;
    

    public async Task Invoke(HttpContext httpContext)
    
        string authHeader = 
            httpContext.Request.Headers["Authorization"];
        if (authHeader != null)
        
            string auth = authHeader.Split(new char[]  ' ' )[1];
            Encoding encoding = Encoding.GetEncoding("UTF-8");
            var usernameAndPassword = 
               encoding.GetString(Convert.FromBase64String(auth));
            string username = usernameAndPassword
                .Split(new char[]  ':' )[0];
            string password = usernameAndPassword
                 .Split(new char[]  ':' )[1];
            if (username == "abc" && password == "123")
            
               await _next(httpContext);
            
            else
            
               httpContext.Response.StatusCode = 401;
               return;
            
        
        else
        
            httpContext.Response.StatusCode = 401;
            return;
        
    

然后在你的 Startup 类的 configure 方法中:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

    app.UseMiddleware<BasicAuthMiddleware>();

【讨论】:

很抱歉延迟了实际尝试这个。首先,设置PreAuthenticate = true 不起作用。有趣的是,我正在使用完全相同的方法调用第三方 API,并且效果很好。但是当它调用我的 Web API 时,没有 Authorization 标头。我的 Web API 根据this article 实现基本身份验证。我很困惑为什么我需要额外的中间件。

以上是关于访问服务器上的 HttpClientHandler.Credentials?的主要内容,如果未能解决你的问题,请参考以下文章

TestServer CreateClient 和 HttpClientHandler - 如何?

HttpClientHandler / 请求被中止:无法创建 SSL/TLS 安全通道

HttpClientHandler / HttpClient 内存泄漏

多个 HttpClientHandler 实例超时错误

HttpClientHandler 抛出 PlatformNotSupportedException

如何在 .NET Core 中使用 HttpClientHandler 和 HttpClientFactory