- Add JWT Bearer token validation to API Gateway with restricted CORS - Add cookie-based JWT validation to FileService for browser image requests - Create shared authentication infrastructure in FictionArchive.Service.Shared - Update frontend to set fa_session cookie after OIDC login - Add [Authorize] attributes to GraphQL mutations with role-based restrictions - Configure OIDC settings for both services in docker-compose Implements FA-17: Authentication for microservices architecture
91 lines
3.7 KiB
C#
91 lines
3.7 KiB
C#
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using FictionArchive.Service.Shared.Models.Authentication;
|
|
|
|
namespace FictionArchive.Service.Shared.Extensions;
|
|
|
|
public static class AuthenticationExtensions
|
|
{
|
|
public static IServiceCollection AddOidcAuthentication(this IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
var oidcConfig = configuration.GetSection("OIDC").Get<OidcConfiguration>();
|
|
|
|
if (oidcConfig == null)
|
|
{
|
|
throw new InvalidOperationException("OIDC configuration is required but not found in app settings");
|
|
}
|
|
|
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
.AddJwtBearer(options =>
|
|
{
|
|
options.Authority = oidcConfig.Authority;
|
|
options.Audience = oidcConfig.Audience;
|
|
options.RequireHttpsMetadata = !string.IsNullOrEmpty(oidcConfig.Authority) && oidcConfig.Authority.StartsWith("https://");
|
|
|
|
options.TokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuer = oidcConfig.ValidateIssuer,
|
|
ValidateAudience = oidcConfig.ValidateAudience,
|
|
ValidateLifetime = oidcConfig.ValidateLifetime,
|
|
ValidateIssuerSigningKey = oidcConfig.ValidateIssuerSigningKey,
|
|
ClockSkew = TimeSpan.FromMinutes(5)
|
|
};
|
|
});
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddOidcCookieAuthentication(this IServiceCollection services, IConfiguration configuration, string cookieName = "fa_session")
|
|
{
|
|
var oidcConfig = configuration.GetSection("OIDC").Get<OidcConfiguration>();
|
|
|
|
if (oidcConfig == null)
|
|
{
|
|
throw new InvalidOperationException("OIDC configuration is required but not found in app settings");
|
|
}
|
|
|
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
.AddJwtBearer(options =>
|
|
{
|
|
options.Authority = oidcConfig.Authority;
|
|
options.Audience = oidcConfig.Audience;
|
|
options.RequireHttpsMetadata = !string.IsNullOrEmpty(oidcConfig.Authority) && oidcConfig.Authority.StartsWith("https://");
|
|
|
|
options.Events = new JwtBearerEvents
|
|
{
|
|
OnMessageReceived = context =>
|
|
{
|
|
// Try to get token from cookie first, then from Authorization header
|
|
if (context.Request.Cookies.ContainsKey(cookieName))
|
|
{
|
|
context.Token = context.Request.Cookies[cookieName];
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
};
|
|
|
|
options.TokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuer = oidcConfig.ValidateIssuer,
|
|
ValidateAudience = oidcConfig.ValidateAudience,
|
|
ValidateLifetime = oidcConfig.ValidateLifetime,
|
|
ValidateIssuerSigningKey = oidcConfig.ValidateIssuerSigningKey,
|
|
ClockSkew = TimeSpan.FromMinutes(5)
|
|
};
|
|
});
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddFictionArchiveAuthorization(this IServiceCollection services)
|
|
{
|
|
services.AddAuthorizationBuilder()
|
|
.AddPolicy("Admin", policy => policy.RequireRole("admin"))
|
|
.AddPolicy("User", policy => policy.RequireAuthenticatedUser());
|
|
|
|
return services;
|
|
}
|
|
} |