Skip to content

Commit

Permalink
Merge pull request #10 from DetNordjyskeMediehus/refactorings
Browse files Browse the repository at this point in the history
Add minimal service implementation and split ApiKeyAuthenticationExtensions
  • Loading branch information
dnmh-admin committed May 4, 2023
2 parents 35ab393 + 844a7a0 commit 988fb2f
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 63 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ To use this library, follow these steps:
1. In your `Startup.cs` file, add the following code to the `ConfigureServices` method:

```csharp
services.AddApiKeyAuthentication<ApiKeyAuthenticationService>()
services.AddAuthentication("ApiKey")
.AddApiKeyAuthentication("MySecretApiKey")
.AddSwaggerAuthorization("Description");
```

Expand Down
4 changes: 2 additions & 2 deletions Samples/Controllers/TestApiKeyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ namespace Dnmh.Security.ApiKeyAuthentication.Sample.Controllers;

[ApiController]
[Route("[controller]")]
[Authorize(AuthenticationSchemes = "ApiKey")]
[Authorize]
public class TestApiKeyController : ControllerBase
{
/// <summary>
/// Tests the ApiKey Authentication.
/// </summary>
[HttpGet]
public string Get() => "Congratulations! You supplied a valid api key!";
public string Get() => "Congratulations! You have supplied a valid api key!";
}
9 changes: 4 additions & 5 deletions Samples/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using Dnmh.Security.ApiKeyAuthentication.AuthenticationHandler;
using Dnmh.Security.ApiKeyAuthentication.Sample.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Adds the default authentication scheme named "ApiKey". This is activated on a controller by using the [Authorize(AuthenticationSchemes = "ApiKey")] attribute.
builder.Services.AddAuthentication()
.AddApiKeyAuthentication<ApiKeyAuthenticationService>()
// Adds the default authentication scheme named "ApiKey". This is activated on a controller by using the [Authorize] attribute.
builder.Services.AddAuthentication("ApiKey")
.AddApiKeyAuthentication(sp => builder.Configuration.GetRequiredSection("MyApiKey").Value!)
.AddSwaggerAuthorization("Please add a valid api key (the valid api key is found in appsettings.json 🤫)");

var app = builder.Build();
Expand All @@ -26,4 +25,4 @@

app.MapControllers();

app.Run();
app.Run();
20 changes: 0 additions & 20 deletions Samples/Services/ApiKeyAuthenticationService.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Authentication;

namespace Dnmh.Security.ApiKeyAuthentication.AuthenticationHandler;

public static partial class ApiKeyAuthenticationExtensions
{
/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a given valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="validApiKey">The valid api key that the api keys provided in the requests are validated against.</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, string validApiKey) =>
builder.AddApiKeyAuthentication(_ => validApiKey);

/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a function to provide a valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="validApiKeyFunction">A function that returns a valid api key. The valid api key is validated against the api keys provided in the requests.</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, Func<IServiceProvider, string> validApiKeyFunction) =>
builder.AddApiKeyAuthentication(sp => new SimpleApiKeyAuthenticationService(validApiKeyFunction?.Invoke(sp) ?? throw new ArgumentNullException(nameof(validApiKeyFunction))));

/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler.
/// </summary>
/// <typeparam name="TAuthService">The implementing class of interface <see cref="IApiKeyAuthenticationService"/></typeparam>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="serviceImplementationFactory">Optional implementation factory for the registration of <typeparamref name="TAuthService"/></param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder, Func<IServiceProvider, TAuthService>? serviceImplementationFactory = null)
where TAuthService : class, IApiKeyAuthenticationService =>
builder.AddApiKeyAuthentication("ApiKey", _ => { }, serviceImplementationFactory);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Authentication;

namespace Dnmh.Security.ApiKeyAuthentication.AuthenticationHandler;

public static partial class ApiKeyAuthenticationExtensions
{
/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a given valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="validApiKey">The valid api key that the api keys provided in the requests are validated against.</param>
/// <param name="configureOptions">The action used to configure options</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, string validApiKey, Action<ApiKeyAuthenticationOptions> configureOptions) =>
builder.AddApiKeyAuthentication(_ => validApiKey, configureOptions);

/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a function to provide a valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="validApiKeyFunction">A function that returns a valid api key. The valid api key is validated against the api keys provided in the requests.</param>
/// <param name="configureOptions">The action used to configure options</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, Func<IServiceProvider, string> validApiKeyFunction, Action<ApiKeyAuthenticationOptions> configureOptions) =>
builder.AddApiKeyAuthentication(configureOptions, sp => new SimpleApiKeyAuthenticationService(validApiKeyFunction?.Invoke(sp) ?? throw new ArgumentNullException(nameof(validApiKeyFunction))));

/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler.
/// </summary>
/// <typeparam name="TAuthService">The implementing class of interface <see cref="IApiKeyAuthenticationService"/></typeparam>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="configureOptions">The action used to configure options</param>
/// <param name="serviceImplementationFactory">Optional implementation factory for the registration of <typeparamref name="TAuthService"/></param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder, Action<ApiKeyAuthenticationOptions> configureOptions, Func<IServiceProvider, TAuthService>? serviceImplementationFactory = null)
where TAuthService : class, IApiKeyAuthenticationService =>
builder.AddApiKeyAuthentication("ApiKey", configureOptions, serviceImplementationFactory);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Authentication;

namespace Dnmh.Security.ApiKeyAuthentication.AuthenticationHandler;

public static partial class ApiKeyAuthenticationExtensions
{
/// <summary>
/// Adds a given authentication scheme name and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a given valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="authenticationScheme">The authentication scheme name</param>
/// <param name="validApiKey">The valid api key that the api keys provided in the requests are validated against.</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, string authenticationScheme, string validApiKey) =>
builder.AddApiKeyAuthentication(authenticationScheme, _ => validApiKey);

/// <summary>
/// Adds a given authentication scheme name and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a function to provide a valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="authenticationScheme">The authentication scheme name</param>
/// <param name="validApiKeyFunction">A function that returns a valid api key. The valid api key is validated against the api keys provided in the requests.</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, string authenticationScheme, Func<IServiceProvider, string> validApiKeyFunction) =>
builder.AddApiKeyAuthentication(authenticationScheme, sp => new SimpleApiKeyAuthenticationService(validApiKeyFunction?.Invoke(sp) ?? throw new ArgumentNullException(nameof(validApiKeyFunction))));

/// <summary>
/// Adds a given authentication scheme name and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler.
/// </summary>
/// <typeparam name="TAuthService">The implementing class of interface <see cref="IApiKeyAuthenticationService"/></typeparam>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="authenticationScheme">The authentication scheme name</param>
/// <param name="serviceImplementationFactory">Optional implementation factory for the registration of <typeparamref name="TAuthService"/></param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder, string authenticationScheme, Func<IServiceProvider, TAuthService>? serviceImplementationFactory = null)
where TAuthService : class, IApiKeyAuthenticationService =>
builder.AddApiKeyAuthentication(authenticationScheme, _ => { }, serviceImplementationFactory);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Authentication;

namespace Dnmh.Security.ApiKeyAuthentication.AuthenticationHandler;

public static partial class ApiKeyAuthenticationExtensions
{
/// <summary>
/// Adds a given authentication scheme name and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a given valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="authenticationScheme">The authentication scheme name</param>
/// <param name="validApiKey">The valid api key that the api keys provided in the requests are validated against.</param>
/// <param name="configureOptions">The action used to configure options</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, string authenticationScheme, string validApiKey, Action<ApiKeyAuthenticationOptions> configureOptions) =>
builder.AddApiKeyAuthentication(authenticationScheme, _ => validApiKey, configureOptions);

/// <summary>
/// Adds a given authentication scheme name and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler
/// with a function to provide a valid api key.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="authenticationScheme">The authentication scheme name</param>
/// <param name="validApiKeyFunction">A function that returns a valid api key. The valid api key is validated against the api keys provided in the requests.</param>
/// <param name="configureOptions">The action used to configure options</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication(this AuthenticationBuilder builder, string authenticationScheme, Func<IServiceProvider, string> validApiKeyFunction, Action<ApiKeyAuthenticationOptions> configureOptions) =>
builder.AddApiKeyAuthentication(authenticationScheme, configureOptions, sp => new SimpleApiKeyAuthenticationService(validApiKeyFunction?.Invoke(sp) ?? throw new ArgumentNullException(nameof(validApiKeyFunction))));
}
43 changes: 11 additions & 32 deletions Source/AuthenticationHandler/ApiKeyAuthenticationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,52 +6,31 @@ namespace Dnmh.Security.ApiKeyAuthentication.AuthenticationHandler;
/// <summary>
/// Extension methods for the <see cref="AuthenticationBuilder"/>
/// </summary>
public static class ApiKeyAuthenticationExtensions
public static partial class ApiKeyAuthenticationExtensions
{
/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler.
/// </summary>
/// <typeparam name="TAuthService">The implementing class of interface <see cref="IApiKeyAuthenticationService"/></typeparam>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder)
where TAuthService : class, IApiKeyAuthenticationService =>
builder.AddApiKeyAuthentication<TAuthService>("ApiKey", _ => { });

/// <summary>
/// Adds a given authentication scheme name and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler.
/// </summary>
/// <typeparam name="TAuthService">The implementing class of interface <see cref="IApiKeyAuthenticationService"/></typeparam>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="authenticationScheme">The authentication scheme name</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder, string authenticationScheme)
where TAuthService : class, IApiKeyAuthenticationService =>
builder.AddApiKeyAuthentication<TAuthService>(authenticationScheme, _ => { });

/// <summary>
/// Adds a default authentication scheme named <c>"ApiKey"</c> and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler.
/// </summary>
/// <typeparam name="TAuthService">The implementing class of interface <see cref="IApiKeyAuthenticationService"/></typeparam>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="configureOptions">The action used to configure options</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder, Action<ApiKeyAuthenticationOptions> configureOptions)
where TAuthService : class, IApiKeyAuthenticationService =>
builder.AddApiKeyAuthentication<TAuthService>("ApiKey", configureOptions);

/// <summary>
/// Adds a given authentication scheme name and registers the <see cref="ApiKeyAuthenticationHandler"/> as the authentication handler.
/// </summary>
/// <typeparam name="TAuthService">The implementing class of interface <see cref="IApiKeyAuthenticationService"/></typeparam>
/// <param name="builder">The <see cref="AuthenticationBuilder"/></param>
/// <param name="authenticationScheme">The authentication scheme name</param>
/// <param name="configureOptions">The action used to configure options</param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder, string authenticationScheme, Action<ApiKeyAuthenticationOptions> configureOptions)
/// <param name="serviceImplementationFactory">Optional implementation factory for the registration of <typeparamref name="TAuthService"/></param>
public static ApiKeyAuthenticationBuilder AddApiKeyAuthentication<TAuthService>(this AuthenticationBuilder builder, string authenticationScheme, Action<ApiKeyAuthenticationOptions> configureOptions, Func<IServiceProvider, TAuthService>? serviceImplementationFactory = null)
where TAuthService : class, IApiKeyAuthenticationService
{
ArgumentNullException.ThrowIfNull(nameof(builder));
ArgumentNullException.ThrowIfNull(nameof(authenticationScheme));
ArgumentNullException.ThrowIfNull(nameof(configureOptions));

builder.Services.AddTransient<IApiKeyAuthenticationService, TAuthService>();
if (serviceImplementationFactory == null)
{
builder.Services.AddTransient<IApiKeyAuthenticationService, TAuthService>();
}
else
{
builder.Services.AddTransient<IApiKeyAuthenticationService, TAuthService>(serviceImplementationFactory);
}

builder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(
authenticationScheme, configureOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
public bool UseAuthorizationHeaderKey { get; set; } = false;

/// <summary>
/// If <c>true</c>, the authentication scheme name given in <see cref="ApiKeyAuthenticationExtensions.AddApiKeyAuthentication{TAuthService}(AuthenticationBuilder, string)"/> is used as Authorization header scheme.
/// If <c>true</c>, the authentication scheme name given in <see cref="ApiKeyAuthenticationExtensions.AddApiKeyAuthentication{TAuthService}(AuthenticationBuilder, string, Action{ApiKeyAuthenticationOptions}, Func{IServiceProvider, TAuthService}?)"/> is used as Authorization header scheme.
/// Requires that <see cref="AllowApiKeyInRequestHeader"/> and <see cref="UseAuthorizationHeaderKey"/> are both <c>true</c>.
/// If this is set to <c>true</c>, then the value in <see cref="AuthorizationSchemeInHeader"/> is ignored.
/// Default is <c>false</c>
Expand Down
Loading

0 comments on commit 988fb2f

Please sign in to comment.