2024-08-21 16:02:56 +00:00
|
|
|
|
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<HttpResponseMessage> 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<bool> AppendTokenAsync(HttpRequestMessage request)
|
|
|
|
|
{
|
|
|
|
|
if (request.Headers.Authorization == null)
|
|
|
|
|
{
|
|
|
|
|
if (UserContext.Instance.AccessToken == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var expiredTime = UserContext.Instance.ExpiredTime;
|
2024-10-25 04:53:49 +00:00
|
|
|
|
if (expiredTime != null && expiredTime - DateTime.UtcNow < _requiredRefreshTime)
|
2024-08-21 16:02:56 +00:00
|
|
|
|
{
|
|
|
|
|
await _refreshSemaphore.WaitAsync();
|
|
|
|
|
bool refreshSuccess;
|
|
|
|
|
{
|
|
|
|
|
expiredTime = UserContext.Instance.ExpiredTime;
|
2024-10-25 04:53:49 +00:00
|
|
|
|
if (expiredTime != null && expiredTime - DateTime.UtcNow < _requiredRefreshTime)
|
2024-08-21 16:02:56 +00:00
|
|
|
|
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<bool> RefreshTokenAsync()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var client = HttpClientFactory.CreateClient(HttpConstants.ClientNames.AuthClient))
|
|
|
|
|
{
|
|
|
|
|
return await client.RefreshTokenAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|