using System.Security.Cryptography; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using SIGCM2.Application.Abstractions; using SIGCM2.Application.Abstractions.Persistence; using SIGCM2.Application.Abstractions.Security; using SIGCM2.Infrastructure.Messaging; using SIGCM2.Infrastructure.Persistence; using SIGCM2.Infrastructure.Security; namespace SIGCM2.Infrastructure; public static class DependencyInjection { public static IServiceCollection AddInfrastructure( this IServiceCollection services, IConfiguration configuration) { // Database var connectionString = configuration.GetConnectionString("SqlServer") ?? throw new InvalidOperationException("Missing ConnectionStrings:SqlServer"); services.AddSingleton(new SqlConnectionFactory(connectionString)); services.AddScoped(); // JWT Options — bound lazily via IOptions so tests can override via ConfigureWebHost services.Configure(configuration.GetSection("Jwt")); // Also expose as JwtOptions directly for convenience (resolves via IOptions) services.AddSingleton(sp => sp.GetRequiredService>().Value); // RSA key pair — loaded lazily as singletons from the fully-resolved JwtOptions services.AddSingleton(sp => { var opts = sp.GetRequiredService(); return RsaKeyLoader.LoadPrivateKey(opts); }); services.AddSingleton(sp => { var opts = sp.GetRequiredService(); return new RsaSecurityKey(RsaKeyLoader.LoadPublicKey(opts)); }); services.AddScoped(sp => new JwtService(sp.GetRequiredService(), sp.GetRequiredService())); services.AddScoped(); // Dispatcher services.AddScoped(); // JWT Bearer authentication services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(); // Post-configure JWT Bearer — wire RSA public key + validation params from resolved options services.AddOptions(JwtBearerDefaults.AuthenticationScheme) .PostConfigure((jwtBearerOpts, rsaKey, jwtOpts) => { jwtBearerOpts.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = rsaKey, ValidateIssuer = true, ValidIssuer = jwtOpts.Issuer, ValidateAudience = true, ValidAudience = jwtOpts.Audience, ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; }); return services; } }