using IdentityModel.Client; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; namespace Gameboard.ShogiUI.Sockets.Repositories.Utility { public interface IAuthenticatedHttpClient { Task DeleteAsync(string requestUri); Task GetAsync(string requestUri); Task PostAsync(string requestUri, HttpContent content); Task PutAsync(string requestUri, HttpContent content); } public class AuthenticatedHttpClient : HttpClient, IAuthenticatedHttpClient { private readonly ILogger logger; private readonly string identityServerUrl; private TokenResponse tokenResponse; private readonly string clientId; private readonly string clientSecret; public AuthenticatedHttpClient(ILogger logger, IConfiguration configuration) : base() { this.logger = logger; identityServerUrl = configuration["AppSettings:IdentityServer"]; clientId = configuration["AppSettings:ClientId"]; clientSecret = configuration["AppSettings:ClientSecret"]; BaseAddress = new Uri(configuration["AppSettings:GameboardShogiApi"]); } private async Task RefreshBearerToken() { var disco = await this.GetDiscoveryDocumentAsync(identityServerUrl); if (disco.IsError) { logger.LogError("{DiscoveryErrorType}", disco.ErrorType); throw new Exception(disco.Error); } var request = new ClientCredentialsTokenRequest { Address = disco.TokenEndpoint, ClientId = clientId, ClientSecret = clientSecret }; var response = await this.RequestClientCredentialsTokenAsync(request); if (response.IsError) { throw new Exception(response.Error); } tokenResponse = response; logger.LogInformation("Refreshing Bearer Token to {BaseAddress}", BaseAddress); this.SetBearerToken(tokenResponse.AccessToken); } public async new Task PutAsync(string requestUri, HttpContent content) { var response = await base.PutAsync(requestUri, content); if (response.StatusCode == HttpStatusCode.Unauthorized) { await RefreshBearerToken(); response = await base.PostAsync(requestUri, content); } logger.LogInformation( "Repository PUT to {BaseUrl}{RequestUrl} \n\tRespCode: {RespCode} \n\tRequest: {Request}\n\tResponse: {Response}\n", BaseAddress, requestUri, response.StatusCode, await content.ReadAsStringAsync(), await response.Content.ReadAsStringAsync()); return response; } public async new Task GetAsync(string requestUri) { var response = await base.GetAsync(requestUri); if (response.StatusCode == HttpStatusCode.Unauthorized) { await RefreshBearerToken(); response = await base.GetAsync(requestUri); } logger.LogInformation( "Repository GET to {BaseUrl}{RequestUrl} \nResponse: {Response}\n", BaseAddress, requestUri, await response.Content.ReadAsStringAsync()); return response; } public async new Task PostAsync(string requestUri, HttpContent content) { var response = await base.PostAsync(requestUri, content); if (response.StatusCode == HttpStatusCode.Unauthorized) { await RefreshBearerToken(); response = await base.PostAsync(requestUri, content); } logger.LogInformation( "Repository POST to {BaseUrl}{RequestUrl} \n\tRespCode: {RespCode} \n\tRequest: {Request}\n\tResponse: {Response}\n", BaseAddress, requestUri, response.StatusCode, await content.ReadAsStringAsync(), await response.Content.ReadAsStringAsync()); return response; } public async new Task DeleteAsync(string requestUri) { var response = await base.DeleteAsync(requestUri); if (response.StatusCode == HttpStatusCode.Unauthorized) { await RefreshBearerToken(); response = await base.DeleteAsync(requestUri); } logger.LogInformation("Repository DELETE to {BaseUrl}{RequestUrl}", BaseAddress, requestUri); return response; } } }