Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authentication per request using HttpClientFactory .net Core 2.1

How should I use HttpClientFactory to return an instance of HttpClient whose uri and credentials are determined at the point of the call?

The existing code looks like this:

var httpClientHandler = new HttpClientHandler()
    {
        Credentials = new NetworkCredential(userName, password),
    };
HttpClient client = new HttpClient(httpClientHandler);
client.BaseAddress = new Uri(_appSetting.ServiceURI);
like image 716
Simon H Avatar asked Dec 04 '22 18:12

Simon H


2 Answers

You can create an authentication delegating handler like this:

public class AuthenticationHttpMessageHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            // Get the token or other type of credentials here
            // string scheme = ... // E.g. "Bearer", "Basic" etc.
            // string credentials = ... // E.g. formatted token, user/password etc.

            request.Headers.Authorization =
                new AuthenticationHeaderValue(scheme, credentials);

            return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
        }
    }

then add it to the HttpClient builder and to the DI container:

 services
     .AddTransient<AuthenticationHttpMessageHandler>()
     .AddHttpClient("MyClient")
     .AddHttpMessageHandler<AuthenticationHttpMessageHandler>();

then use IHttpClientFactory to create HttpClient instances.

The core advantage of this approach is that you clearly separate concerns. You don't touch the primary handler, you don't manage client creation manually, you utilize the whole power of the factory and its builder extension methods. The authentication handler is naturally injected in the pipeline and adds authorization to each request. This handler can be enhanced further by abstracting away the source of credentials and make the handler depend on some IAuthenticationProvider abstraction, which will require only DI configuration and not touching the HttpClient configuration code.

like image 26
sich Avatar answered Dec 06 '22 09:12

sich


your ConfigureServices method in Start up class

             services.AddHttpClient("github", c =>
            {
                //c.BaseAddress = new Uri("https://api.github.com/");
                c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
                c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
                
            }).ConfigurePrimaryHttpMessageHandler(() =>
            {
                return new HttpClientHandler()
                {
                    UseDefaultCredentials = true,
                    Credentials = new NetworkCredential("", ""),
                };
            });

Your Controller will look like this

 private readonly IHttpClientFactory _httpClientFactory;

        public DataProController(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }

        [HttpGet]
        public async Task<ActionResult> Get()
        {            
            var client = _httpClientFactory.CreateClient("github");
            
            client.BaseAddress = new Uri("https://api.github.com/");

            string result = await client.GetStringAsync("/");
            return Ok(result);
        }

You may not be able to set up Network Credentials at the run time when using httpclientfactory and may need to setup up in the startup class. you can find about this issue here. https://github.com/aspnet/HttpClientFactory/issues/71

like image 184
Imran Arshad Avatar answered Dec 06 '22 09:12

Imran Arshad