Skip to content

Commit

Permalink
refactoring to 2.1.0 version
Browse files Browse the repository at this point in the history
  • Loading branch information
Adolfok3 committed Apr 27, 2024
1 parent 8515aed commit 5fb81b7
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 161 deletions.
12 changes: 6 additions & 6 deletions samples/SourceApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,38 +80,38 @@ public async Task<AuthorizationHeaders> UnauthenticateAsync(AuthorizationHeaders
}
public class CustomInterceptor1 : IAuthorizationInterceptor
{
public Task<AuthorizationHeaders?> GetHeadersAsync()
public Task<AuthorizationHeaders?> GetHeadersAsync(string name)
{
return Task.FromResult<AuthorizationHeaders?>(null);
}

public Task UpdateHeadersAsync(AuthorizationHeaders? expiredHeaders, AuthorizationHeaders? newHeaders)
public Task UpdateHeadersAsync(string name, AuthorizationHeaders? expiredHeaders, AuthorizationHeaders? newHeaders)
{
return Task.CompletedTask;
}
}

public class CustomInterceptor2 : IAuthorizationInterceptor
{
public Task<AuthorizationHeaders?> GetHeadersAsync()
public Task<AuthorizationHeaders?> GetHeadersAsync(string name)
{
return Task.FromResult<AuthorizationHeaders?>(null);
}

public Task UpdateHeadersAsync(AuthorizationHeaders? expiredHeaders, AuthorizationHeaders? newHeaders)
public Task UpdateHeadersAsync(string name, AuthorizationHeaders? expiredHeaders, AuthorizationHeaders? newHeaders)
{
return Task.CompletedTask;
}
}

public class CustomInterceptor3 : IAuthorizationInterceptor
{
public Task<AuthorizationHeaders?> GetHeadersAsync()
public Task<AuthorizationHeaders?> GetHeadersAsync(string name)
{
return Task.FromResult<AuthorizationHeaders?>(null);
}

public Task UpdateHeadersAsync(AuthorizationHeaders? expiredHeaders, AuthorizationHeaders? newHeaders)
public Task UpdateHeadersAsync(string name, AuthorizationHeaders? expiredHeaders, AuthorizationHeaders? newHeaders)
{
return Task.CompletedTask;
}
Expand Down
4 changes: 2 additions & 2 deletions src/AuthorizationInterceptor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>2.0.0</Version>
<Version>2.1.0</Version>
<TargetFrameworks>net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand All @@ -18,7 +18,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AuthorizationInterceptor.Extensions.Abstractions" Version="0.0.1-beta1" />
<PackageReference Include="AuthorizationInterceptor.Extensions.Abstractions" Version="2.1.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
Expand Down
35 changes: 17 additions & 18 deletions src/Extensions/HttpClientBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using AuthorizationInterceptor.Options;
using AuthorizationInterceptor.Strategies;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -26,34 +26,33 @@ public static class HttpClientBuilderExtensions
public static IHttpClientBuilder AddAuthorizationInterceptorHandler<T>(this IHttpClientBuilder builder, Action<AuthorizationInterceptorOptions>? options = null)
where T : class, IAuthenticationHandler
{
options ??= (options => new AuthorizationInterceptorOptions());
var optionsInstance = new AuthorizationInterceptorOptions();
options.Invoke(optionsInstance);

AddInterceptorsDependencies(builder, optionsInstance._interceptors.Select(s => s.Item2).ToList());
builder.AddHttpMessageHandler(provider => new AuthorizationInterceptorHandler(optionsInstance, new AuthorizationInterceptorStrategy((IAuthenticationHandler)ActivatorUtilities.CreateInstance(provider, typeof(T)), provider.GetRequiredService<ILoggerFactory>(), CreateInterceptorsIntances(provider, optionsInstance._interceptors)), provider.GetRequiredService<ILoggerFactory>()));
var optionsInstance = RequireOptions(options);
AddInterceptorsDependencies(builder, optionsInstance._interceptors);
builder.Services.TryAddTransient<IAuthorizationInterceptorStrategy, AuthorizationInterceptorStrategy>();
builder.AddHttpMessageHandler(provider => ActivatorUtilities.CreateInstance<AuthorizationInterceptorHandler>(provider, builder.Name, optionsInstance.UnauthenticatedPredicate, ActivatorUtilities.CreateInstance(provider, typeof(T))));

return builder;
}

private static void AddInterceptorsDependencies(IHttpClientBuilder builder, List<Func<IServiceCollection, IServiceCollection>?> dependencies)
private static AuthorizationInterceptorOptions RequireOptions(Action<AuthorizationInterceptorOptions>? options)
{
foreach (var dependency in dependencies)
{
dependency?.Invoke(builder.Services);
}
options ??= (options => new AuthorizationInterceptorOptions());
var optionsInstance = new AuthorizationInterceptorOptions();
options.Invoke(optionsInstance);

return optionsInstance;
}

private static IAuthorizationInterceptor[] CreateInterceptorsIntances(IServiceProvider provider, List<(Type, Func<IServiceCollection, IServiceCollection>?)> interceptors)
private static void AddInterceptorsDependencies(IHttpClientBuilder builder, List<(ServiceDescriptor serviceDescriptor, Func<IServiceCollection, IServiceCollection>? dependencies)> interceptors)
{
List<IAuthorizationInterceptor> interceptorsInstances = new();

foreach (var interceptor in interceptors)
{
interceptorsInstances.Add((IAuthorizationInterceptor)ActivatorUtilities.CreateInstance(provider, interceptor.Item1));
if (!builder.Services.Any(a => a.ServiceType == typeof(IAuthorizationInterceptor) && a.ImplementationType == interceptor.serviceDescriptor.ImplementationType))
{
builder.Services.Add(interceptor.serviceDescriptor);
interceptor.dependencies?.Invoke(builder.Services);
}
}

return interceptorsInstances.ToArray();
}
}
}
Expand Down
35 changes: 20 additions & 15 deletions src/Handlers/AuthorizationInterceptorHandler.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using AuthorizationInterceptor.Extensions.Abstractions.Headers;
using AuthorizationInterceptor.Options;
using AuthorizationInterceptor.Extensions.Abstractions.Handlers;
using AuthorizationInterceptor.Extensions.Abstractions.Headers;
using AuthorizationInterceptor.Strategies;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading;
Expand All @@ -11,15 +12,19 @@ namespace AuthorizationInterceptor.Handlers
{
internal class AuthorizationInterceptorHandler : DelegatingHandler
{
private readonly AuthorizationInterceptorOptions _options;
private readonly string _name;
private readonly Func<HttpResponseMessage, bool> _unauthenticatedPredicate;
private readonly IAuthenticationHandler _authenticationHandler;
private readonly IAuthorizationInterceptorStrategy _strategy;
private readonly ILogger _logger;
private readonly ILogger<AuthorizationInterceptorHandler> _logger;

public AuthorizationInterceptorHandler(AuthorizationInterceptorOptions options, IAuthorizationInterceptorStrategy strategy, ILoggerFactory loggerFactory)
public AuthorizationInterceptorHandler(string name, Func<HttpResponseMessage, bool> unauthenticatedPredicate, IAuthenticationHandler authenticationHandler, IAuthorizationInterceptorStrategy strategy, ILogger<AuthorizationInterceptorHandler> logger)
{
_options = options;
_name = name;
_logger = logger;
_strategy = strategy;
_logger = loggerFactory.CreateLogger(nameof(AuthorizationInterceptorHandler));
_authenticationHandler = authenticationHandler;
_unauthenticatedPredicate = unauthenticatedPredicate;
}

protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
Expand All @@ -34,24 +39,24 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage

private async Task<HttpResponseMessage> SendWithInterceptorAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var headers = await _strategy.GetHeadersAsync();
var headers = await _strategy.GetHeadersAsync(_name, _authenticationHandler);
if (headers == null || !headers.Any())
{
Log("No headers added to request");
LogDebug("No headers added to request with integration '{name}'", _name);
return await base.SendAsync(request, cancellationToken);
}

request = AddHeaders(request, headers);

var response = await base.SendAsync(request, cancellationToken);
if (!_options.UnauthenticatedPredicate(response))
if (!_unauthenticatedPredicate(response))
return response;

Log("Caught unauthenticated predicate from response");
headers = await _strategy.UpdateHeadersAsync(headers);
LogDebug("Caught unauthenticated predicate from response with integration '{name}'", _name);
headers = await _strategy.UpdateHeadersAsync(_name, headers, _authenticationHandler);
if (headers == null || !headers.Any())
{
Log("No headers added to request");
LogDebug("No headers added to request with integration '{name}'", _name);
return response;
}

Expand All @@ -64,15 +69,15 @@ private HttpRequestMessage AddHeaders(HttpRequestMessage request, AuthorizationH
{
foreach (var header in headers)
{
Log("Adding header '{header}' to request", header.Key);
LogDebug("Adding header '{header}' to request with integration '{name}'", header.Key, _name);
request.Headers.Remove(header.Key);
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}

return request;
}

private void Log(string message, params object[] objs)
private void LogDebug(string message, params object[] objs)
{
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug(message, objs);
Expand Down
6 changes: 3 additions & 3 deletions src/Options/AuthorizationInterceptorOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace AuthorizationInterceptor.Options
/// </summary>
public class AuthorizationInterceptorOptions : IAuthorizationInterceptorOptions
{
internal readonly List<(Type, Func<IServiceCollection, IServiceCollection>?)> _interceptors = new();
internal readonly List<(ServiceDescriptor, Func<IServiceCollection, IServiceCollection>?)> _interceptors = new();

/// <summary>
/// Defines a predicate to know when the request was unauthenticated. If this happens, a new authorization header will be generated. Default is response with <see cref="HttpStatusCode.Unauthorized"/>.
Expand All @@ -23,9 +23,9 @@ public class AuthorizationInterceptorOptions : IAuthorizationInterceptorOptions
/// <summary>
/// <inheritdoc />
/// </summary>
public void UseCustomInterceptor<T>(Func<IServiceCollection, IServiceCollection>? func = null) where T : IAuthorizationInterceptor
public void UseCustomInterceptor<T>(Func<IServiceCollection, IServiceCollection>? services = null) where T : IAuthorizationInterceptor
{
_interceptors.Add((typeof(T), func));
_interceptors.Add((new ServiceDescriptor(typeof(IAuthorizationInterceptor), typeof(T), ServiceLifetime.Transient), services));
}
}
}
Expand Down
48 changes: 23 additions & 25 deletions src/Strategies/AuthorizationInterceptorStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,24 @@
using AuthorizationInterceptor.Extensions.Abstractions.Interceptors;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AuthorizationInterceptor.Strategies
{
internal class AuthorizationInterceptorStrategy : IAuthorizationInterceptorStrategy
{
private readonly IAuthorizationInterceptor[] _interceptors;
private readonly IAuthenticationHandler _authenticationHandler;
private readonly ILogger _logger;
private readonly string _authenticationHandlerName;
private readonly ILogger<AuthorizationInterceptorStrategy> _logger;

public AuthorizationInterceptorStrategy(IAuthenticationHandler authenticationHandler, ILoggerFactory loggerFactory, IAuthorizationInterceptor[] interceptors)
public AuthorizationInterceptorStrategy(ILogger<AuthorizationInterceptorStrategy> logger, IEnumerable<IAuthorizationInterceptor> interceptors)
{
_authenticationHandler = authenticationHandler;
_interceptors = interceptors;
_logger = loggerFactory.CreateLogger(nameof(AuthorizationInterceptorStrategy));
_authenticationHandlerName = _authenticationHandler.GetType().Name;
_logger = logger;
_interceptors = interceptors.ToArray();
}

public async Task<AuthorizationHeaders?> GetHeadersAsync()
public async Task<AuthorizationHeaders?> GetHeadersAsync(string name, IAuthenticationHandler authenticationHandler)
{
AuthorizationHeaders? headers;
int index;
Expand All @@ -31,34 +29,34 @@ public AuthorizationInterceptorStrategy(IAuthenticationHandler authenticationHan
{
try
{
Log("Getting headers from {interceptor}", _interceptors[index].GetType().Name);
headers = await _interceptors[index].GetHeadersAsync();
LogDebug("Getting headers from interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
headers = await _interceptors[index].GetHeadersAsync(name);
if (headers != null)
return await UpdateHeadersInInterceptorsAsync(index, headers);
return await UpdateHeadersInInterceptorsAsync(name, index, headers);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error on getting headers from {interceptor}", _interceptors[index].GetType().Name);
_logger.LogError(ex, "Error getting headers from interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
}
}

Log("Getting headers from {authenticationHandler}", _authenticationHandlerName);
LogDebug("Getting headers from AuthenticationHandler '{authenticationHandler}' with integration '{name}'", authenticationHandler.GetType().Name, name);

headers = await _authenticationHandler.AuthenticateAsync();
return await UpdateHeadersInInterceptorsAsync(index, headers);
headers = await authenticationHandler.AuthenticateAsync();
return await UpdateHeadersInInterceptorsAsync(name, index, headers);
}

public async Task<AuthorizationHeaders?> UpdateHeadersAsync(AuthorizationHeaders? expiredHeaders)
public async Task<AuthorizationHeaders?> UpdateHeadersAsync(string name, AuthorizationHeaders? expiredHeaders, IAuthenticationHandler authenticationHandler)
{
Log("Getting new headers from {authenticationHandler}", _authenticationHandlerName);
var newHeaders = await _authenticationHandler.UnauthenticateAsync(expiredHeaders);
LogDebug("Getting new headers from AuthenticationHandler '{authenticationHandler}' with integration '{name}'", authenticationHandler.GetType().Name, name);
var newHeaders = await authenticationHandler.UnauthenticateAsync(expiredHeaders);
if (newHeaders == null)
return null;

return await UpdateHeadersInInterceptorsAsync(_interceptors.Length, newHeaders);
return await UpdateHeadersInInterceptorsAsync(name, _interceptors.Length, newHeaders);
}

private async Task<AuthorizationHeaders?> UpdateHeadersInInterceptorsAsync(int startIndex, AuthorizationHeaders? headers = null)
private async Task<AuthorizationHeaders?> UpdateHeadersInInterceptorsAsync(string name, int startIndex, AuthorizationHeaders? headers = null)
{
if (headers == null)
return null;
Expand All @@ -67,19 +65,19 @@ public AuthorizationInterceptorStrategy(IAuthenticationHandler authenticationHan
{
try
{
Log("Updating headers in {interceptor}", _interceptors[index].GetType().Name);
await _interceptors[index].UpdateHeadersAsync(null, headers);
LogDebug("Updating headers in interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
await _interceptors[index].UpdateHeadersAsync(name, null, headers);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error on updating headers in {interceptor}", _interceptors[index].GetType().Name);
_logger.LogError(ex, "Error updating headers in interceptor '{interceptor}' with integration '{name}'", _interceptors[index].GetType().Name, name);
}
}

return headers;
}

private void Log(string message, params object[] parameters)
private void LogDebug(string message, params object[] parameters)
{
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug(message, parameters);
Expand Down
7 changes: 4 additions & 3 deletions src/Strategies/IAuthorizationInterceptorStrategy.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using AuthorizationInterceptor.Extensions.Abstractions.Headers;
using AuthorizationInterceptor.Extensions.Abstractions.Handlers;
using AuthorizationInterceptor.Extensions.Abstractions.Headers;
using System.Threading.Tasks;

namespace AuthorizationInterceptor.Strategies
{
internal interface IAuthorizationInterceptorStrategy
{
Task<AuthorizationHeaders?> GetHeadersAsync();
Task<AuthorizationHeaders?> GetHeadersAsync(string name, IAuthenticationHandler authenticationHandler);

Task<AuthorizationHeaders?> UpdateHeadersAsync(AuthorizationHeaders? expiredHeaders);
Task<AuthorizationHeaders?> UpdateHeadersAsync(string name, AuthorizationHeaders? expiredHeaders, IAuthenticationHandler authenticationHandler);
}
}
Loading

0 comments on commit 5fb81b7

Please sign in to comment.