WebApi + ClientApp, GraphQL, Reflection

This commit is contained in:
Boris Milašinović
2026-05-06 20:55:05 +02:00
parent 8f7c704a90
commit 4fb3de19f6
196 changed files with 10395 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
namespace Events.WebAPI.Util.Startup;
public static class AuthSetupExtensions
{
public static void SetupAuthenticationAndAuthorization(this IServiceCollection services, IConfiguration configuration)
{
Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddScoped<IClaimsTransformation, ScopeClaimsTransformation>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.Authority = configuration["Auth:Authority"];
opt.Audience = configuration["Auth:Audience"];
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidateIssuerSigningKey = true,
NameClaimType = ClaimTypes.NameIdentifier
};
opt.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Append("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
services.AddAuthorization(options =>
{
foreach (var policy in Policies.All)
{
options.AddPolicy(policy.Key, policy.Value);
}
});
}
}

View File

@@ -0,0 +1,36 @@
using Events.WebAPI.Util.Settings;
using MassTransit;
using Microsoft.Extensions.Options;
namespace Events.WebAPI.Util.Startup;
public static class MassTransitSetupExtensions
{
public static void SetupMassTransit(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions<RabbitMqSettings>()
.Bind(configuration.GetSection("RabbitMq"))
.ValidateDataAnnotations()
.Validate(
settings => Uri.TryCreate(settings.Host, UriKind.Absolute, out var uri) &&
uri.Scheme == "rabbitmq" &&
!string.IsNullOrWhiteSpace(uri.Host),
"RabbitMq:Host must be a valid absolute rabbitmq:// URI.")
.ValidateOnStart();
services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
var settings = context.GetRequiredService<IOptions<RabbitMqSettings>>().Value;
cfg.Host(new Uri(settings.Host), h =>
{
h.Username(settings.Username);
h.Password(settings.Password);
});
});
});
}
}

View File

@@ -0,0 +1,47 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
namespace Events.WebAPI.Util.Startup;
public sealed class ScopeClaimsTransformation : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (principal.Identity is not ClaimsIdentity identity || !identity.IsAuthenticated)
{
return Task.FromResult(principal);
}
Claim[] combinedScopeClaims = identity
.FindAll("scope")
.Where(claim => claim.Value.Contains(' '))
.ToArray();
if (combinedScopeClaims.Length == 0)
{
return Task.FromResult(principal);
}
var additionalIdentity = new ClaimsIdentity();
foreach (Claim combinedClaim in combinedScopeClaims)
{
foreach (string scope in combinedClaim.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
if (identity.HasClaim("scope", scope) || additionalIdentity.HasClaim("scope", scope))
{
continue;
}
additionalIdentity.AddClaim(new Claim("scope", scope, combinedClaim.ValueType, combinedClaim.Issuer));
}
}
if (additionalIdentity.Claims.Any())
{
principal.AddIdentity(additionalIdentity);
}
return Task.FromResult(principal);
}
}