Added auth

This commit is contained in:
2026-05-29 16:02:34 +02:00
parent 4ad6e8a20f
commit 21f4855cc6
13 changed files with 281 additions and 1 deletions
@@ -0,0 +1,37 @@
using System.ComponentModel.DataAnnotations;
namespace WebApi.Authentication;
public sealed class AuthenticationConfiguration
{
public const string SectionName = "Authentication";
[Required]
[Url]
public required string MetadataAddress { get; init; }
[Required]
public required string IssuerAddress { get; init; }
[Required]
public required string AudienceAddress { get; init; }
[Required]
public required string ClientId { get; init; }
public string? ClientSecret { get; init; }
[Required]
[Url]
public required string AuthorizationEndpoint { get; init; }
[Required]
[Url]
public required string TokenEndpoint { get; init; }
[Required]
[MinLength(1)]
public required string[] Scopes { get; init; }
public bool RequireHttpsMetadata { get; init; } = true;
}
@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
namespace WebApi.Authentication;
public static class AuthenticationExtensions
{
public static IServiceCollection AddAuthenticationConfiguration(
this IServiceCollection services,
IConfiguration configuration)
{
services
.AddOptionsWithValidateOnStart<AuthenticationConfiguration>()
.Bind(configuration.GetRequiredSection(AuthenticationConfiguration.SectionName))
.ValidateDataAnnotations();
services.AddSingleton(serviceProvider =>
serviceProvider.GetRequiredService<IOptions<AuthenticationConfiguration>>().Value);
services.AddScoped<JwtBearerEventsHandler>();
services.ConfigureOptions<JwtBearerOptionsSetup>();
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer();
services.AddAuthorization();
return services;
}
}
@@ -0,0 +1,25 @@
using Mediator;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Musify.Application.Users.Commands;
using System.Security.Claims;
namespace WebApi.Authentication;
public sealed class JwtBearerEventsHandler(IMediator mediator) : JwtBearerEvents
{
public override async Task TokenValidated(TokenValidatedContext tokenValidatedContext)
{
var principal = tokenValidatedContext.Principal!;
var id = principal.FindFirstValue(ClaimTypes.NameIdentifier)!;
var guidId = Guid.Parse(id);
var username = principal.FindFirstValue(ClaimTypes.Name)!;
var firstName = principal.FindFirstValue(ClaimTypes.GivenName);
var lastName = principal.FindFirstValue(ClaimTypes.Surname);
await mediator.Send(
new CreateUserCommand(guidId, username, firstName, lastName),
tokenValidatedContext.HttpContext.RequestAborted);
}
}
@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
namespace WebApi.Authentication;
public sealed class JwtBearerOptionsSetup(IOptions<AuthenticationConfiguration> options)
: IConfigureNamedOptions<JwtBearerOptions>
{
private readonly AuthenticationConfiguration _configuration = options.Value;
public void Configure(string? name, JwtBearerOptions options)
{
if (name != JwtBearerDefaults.AuthenticationScheme)
{
return;
}
Configure(options);
}
public void Configure(JwtBearerOptions options)
{
options.MetadataAddress = _configuration.MetadataAddress;
options.RequireHttpsMetadata = _configuration.RequireHttpsMetadata;
options.Audience = _configuration.AudienceAddress;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = _configuration.IssuerAddress,
ValidAudience = _configuration.AudienceAddress,
RoleClaimType = ClaimTypes.Role,
NameClaimType = ClaimTypes.Name,
};
options.EventsType = typeof(JwtBearerEventsHandler);
}
}