using API.Database; using API.Models; using API.Security; using API.Services; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.HttpLogging; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddJsonFile("appsettings.custom.json", optional: true, reloadOnChange: true); builder.Logging.ClearProviders(); builder.Logging.AddSimpleConsole(options => { options.SingleLine = true; options.TimestampFormat = "yyyy-MM-dd HH:mm:ss "; }); builder.Logging.AddDebug(); var connectionString = builder.Configuration.GetConnectionString("Postgres") ?? throw new InvalidOperationException("Connection string 'Postgres' wurde nicht gefunden."); builder.Services.AddDbContext(options => { options.UseNpgsql(connectionString); }); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddHttpLogging(options => { options.LoggingFields = HttpLoggingFields.RequestMethod | HttpLoggingFields.RequestPath | HttpLoggingFields.ResponseStatusCode | HttpLoggingFields.Duration; }); builder.Services .AddIdentity>(options => { options.Password.RequiredLength = 8; options.Password.RequireDigit = false; options.Password.RequireUppercase = false; options.Password.RequireLowercase = false; options.Password.RequireNonAlphanumeric = false; options.User.RequireUniqueEmail = false; options.SignIn.RequireConfirmedAccount = false; options.SignIn.RequireConfirmedEmail = false; }) .AddEntityFrameworkStores() .AddDefaultTokenProviders(); builder.Services.AddAuthorization(options => { options.AddPolicy(PolicyNames.AdminOnly, policy => { policy.RequireRole(RoleNames.Admin); }); }); builder.Services.ConfigureApplicationCookie(options => { options.Cookie.Name = "hoard.auth"; options.LoginPath = "/auth/login"; options.LogoutPath = "/auth/logout"; options.AccessDeniedPath = "/auth/forbidden"; options.SlidingExpiration = true; options.Cookie.HttpOnly = true; options.Events = new CookieAuthenticationEvents { OnRedirectToLogin = context => { if (IsApiRequest(context.Request)) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; return Task.CompletedTask; } context.Response.Redirect(context.RedirectUri); return Task.CompletedTask; }, OnRedirectToAccessDenied = context => { if (IsApiRequest(context.Request)) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return Task.CompletedTask; } context.Response.Redirect(context.RedirectUri); return Task.CompletedTask; } }; }); builder.Services.AddScoped(); var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var startupLogger = scope.ServiceProvider.GetRequiredService>(); var dbContext = scope.ServiceProvider.GetRequiredService(); startupLogger.LogInformation("Starte Datenbankmigrationen."); dbContext.Database.Migrate(); var seedService = scope.ServiceProvider.GetRequiredService(); await seedService.SeedAsync(); startupLogger.LogInformation("Backend-Initialisierung abgeschlossen."); } var webRootPath = app.Environment.WebRootPath ?? Path.Combine(app.Environment.ContentRootPath, "wwwroot"); var indexFilePath = Path.Combine(webRootPath, "index.html"); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseDefaultFiles(); app.UseStaticFiles(); app.UseHttpLogging(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.MapFallback(async context => { if (context.Request.Path.StartsWithSegments("/api")) { context.Response.StatusCode = StatusCodes.Status404NotFound; return; } if (!File.Exists(indexFilePath)) { context.Response.StatusCode = StatusCodes.Status404NotFound; return; } context.Response.ContentType = "text/html; charset=utf-8"; await context.Response.SendFileAsync(indexFilePath); }); app.Run(); static bool IsApiRequest(HttpRequest request) { return request.Path.StartsWithSegments("/api") || request.Path.StartsWithSegments("/auth"); }