using System.Text; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using ROLAC.API.Data; using ROLAC.API.Data.Interceptors; using ROLAC.API.Entities; using ROLAC.API.Services; var builder = WebApplication.CreateBuilder(args); var config = builder.Configuration; // --------------------------------------------------------------------------- // Database // --------------------------------------------------------------------------- builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped(); builder.Services.AddDbContext((sp, opt) => opt.UseNpgsql(config.GetConnectionString("DefaultConnection")) .AddInterceptors(sp.GetRequiredService())); // --------------------------------------------------------------------------- // Identity // --------------------------------------------------------------------------- builder.Services .AddIdentity(opt => { opt.Password.RequiredLength = 8; opt.Password.RequireDigit = true; opt.Password.RequireUppercase = true; opt.Password.RequireLowercase = true; opt.Password.RequireNonAlphanumeric = true; opt.User.RequireUniqueEmail = true; opt.SignIn.RequireConfirmedAccount = false; }) .AddEntityFrameworkStores() .AddDefaultTokenProviders(); // --------------------------------------------------------------------------- // JWT Authentication // --------------------------------------------------------------------------- var jwtKey = config["Jwt:SecretKey"] ?? throw new InvalidOperationException("Jwt:SecretKey is not configured."); builder.Services .AddAuthentication(opt => { opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(opt => { opt.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = config["Jwt:Issuer"], ValidAudience = config["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)), // Roles were written as JWT short name "role"; map to ClaimTypes.Role for [Authorize]. RoleClaimType = "role", ClockSkew = TimeSpan.Zero, }; }); // --------------------------------------------------------------------------- // CORS // --------------------------------------------------------------------------- var allowedOrigins = config.GetSection("Cors:AllowedOrigins").Get() ?? ["http://localhost:4200"]; builder.Services.AddCors(opt => opt.AddPolicy("Angular", policy => policy.WithOrigins(allowedOrigins) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials())); // --------------------------------------------------------------------------- // Application services // --------------------------------------------------------------------------- builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // --------------------------------------------------------------------------- // Swagger / MVC // --------------------------------------------------------------------------- builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(opt => { opt.SwaggerDoc("v1", new() { Title = "ROLAC API", Version = "v1" }); // Enable JWT in Swagger UI opt.AddSecurityDefinition("Bearer", new() { Name = "Authorization", Type = Microsoft.OpenApi.Models.SecuritySchemeType.Http, Scheme = "Bearer", BearerFormat = "JWT", In = Microsoft.OpenApi.Models.ParameterLocation.Header, Description = "Enter your JWT access token.", }); opt.AddSecurityRequirement(new() { { new() { Reference = new() { Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme, Id = "Bearer" } }, [] } }); }); // --------------------------------------------------------------------------- // Build // --------------------------------------------------------------------------- var app = builder.Build(); // Apply migrations + seed on startup using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); await db.Database.MigrateAsync(); await DbSeeder.SeedAsync(scope.ServiceProvider); } if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseCors("Angular"); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();