using Http.Core.Constants; using Http.Core.Contexts; using Http.Core.Extensions; using System; using System.Net.Http; using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; namespace Http.Core.Handlers { public class AuthenticationHandler : DelegatingHandler { public static readonly TimeSpan _requiredRefreshTime = TimeSpan.FromMinutes(5); protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var shouldContinue = await AppendTokenAsync(request); if (!shouldContinue) return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized); return await base.SendAsync(request, cancellationToken); } private static readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1); private async Task AppendTokenAsync(HttpRequestMessage request) { if (request.Headers.Authorization == null) { if (UserContext.Instance.AccessToken == null) return false; var expiredTime = UserContext.Instance.ExpiredTime; if (expiredTime != null && expiredTime - DateTime.UtcNow < _requiredRefreshTime) { await _refreshSemaphore.WaitAsync(); bool refreshSuccess; { expiredTime = UserContext.Instance.ExpiredTime; if (expiredTime != null && expiredTime - DateTime.UtcNow < _requiredRefreshTime) refreshSuccess = await RefreshTokenAsync(); else refreshSuccess = true; // Some other thread already refreshed token } _refreshSemaphore.Release(); if (!refreshSuccess) return false; } request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", UserContext.Instance.AccessToken); return true; } return true; } private async Task RefreshTokenAsync() { try { using (var client = HttpClientFactory.CreateClient(HttpConstants.ClientNames.AuthClient)) { return await client.RefreshTokenAsync(); } } catch { } return false; } } }