using System.Net; using System.Text.Json; using System.Text; using MesaFabApproval.Shared.Models; using Microsoft.Extensions.Caching.Memory; using System.Net.Http.Headers; using MesaFabApproval.Client.Services; using Microsoft.AspNetCore.Components; using MudBlazor; using System.Net.Http; namespace MesaFabApproval.Client.Utilities; public class ApiHttpClientHandler : DelegatingHandler { private readonly IMemoryCache _cache; private readonly IAuthenticationService _authService; private readonly IHttpClientFactory _httpClientFactory; private readonly ISnackbar _snackbar; private readonly MesaFabApprovalAuthStateProvider _authStateProvider; private readonly NavigationManager _navigationManager; private readonly string _apiBaseUrl; public ApiHttpClientHandler(IMemoryCache cache, IConfiguration config, IAuthenticationService authService, IHttpClientFactory httpClientFactory, ISnackbar snackbar, MesaFabApprovalAuthStateProvider authStateProvider, NavigationManager navigationManager) { _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); _apiBaseUrl = config["FabApprovalApiBaseUrl"] ?? throw new NullReferenceException("FabApprovalApiBaseUrl not found in config"); _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected"); _snackbar = snackbar ?? throw new ArgumentNullException("ISnackbar not injected"); _authService = authService ?? throw new ArgumentNullException("IAuthenticationService not injected"); _authStateProvider = authStateProvider ?? throw new ArgumentNullException("MesaFabApprovalAuthStateProvider not injected"); _navigationManager = navigationManager ?? throw new ArgumentNullException("NavigationManager not injected"); } protected override async Task SendAsync(HttpRequestMessage requestMessage, CancellationToken cancellationToken) { AuthTokens? authTokens = await _authService.GetAuthTokens(); HttpRequestMessage initialRequestMessage = new() { Content = requestMessage.Content, Method = requestMessage.Method, RequestUri = requestMessage.RequestUri }; if (authTokens is not null) { initialRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken); requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken); } HttpClient initialClient = _httpClientFactory.CreateClient("API_Handler"); HttpResponseMessage responseMessage = await initialClient.SendAsync(initialRequestMessage, cancellationToken); HttpClient refreshClient = _httpClientFactory.CreateClient("API_Handler"); if (responseMessage.StatusCode.Equals(HttpStatusCode.Unauthorized)) { string? loginId = await _authService.GetLoginId(); if (!string.IsNullOrWhiteSpace(loginId)) { AuthAttempt authAttempt = new() { LoginID = loginId, AuthTokens = authTokens }; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/refresh"); request.Content = new StringContent(JsonSerializer.Serialize(authAttempt), Encoding.UTF8, "application/json"); if (authTokens is not null) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authTokens.JwtToken); } HttpResponseMessage httpResponseMessage = await refreshClient.SendAsync(request, cancellationToken); string responseContent = await httpResponseMessage.Content.ReadAsStringAsync(); if (httpResponseMessage.IsSuccessStatusCode) { JsonSerializerOptions jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true }; LoginResult loginResult = JsonSerializer.Deserialize(responseContent, jsonSerializerOptions) ?? throw new Exception("unable to parse login result from API response"); if (!loginResult.IsAuthenticated) throw new Exception($"User with Login ID {loginId} not authorized"); if (loginResult.AuthTokens is not null) { requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", loginResult.AuthTokens.JwtToken); await _authService.SetTokens(loginResult.AuthTokens.JwtToken, loginResult.AuthTokens.RefreshToken); } if (loginResult.User is not null) await _authService.SetCurrentUser(loginResult.User); } else { await _authStateProvider.Logout(); string? redirectUrl = _cache.Get("redirectUrl"); if (!string.IsNullOrWhiteSpace(redirectUrl)) { _navigationManager.NavigateTo($"login/{redirectUrl}"); } else { _navigationManager.NavigateTo("login"); } } } return await base.SendAsync(requestMessage, cancellationToken); } initialClient.Dispose(); refreshClient.Dispose(); return responseMessage; } }