using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using System.Text; using Webshop.Application.Services.Public; // ProductService using Webshop.Application.Services.Auth; // IAuthService, AuthService using Webshop.Application.Services.Admin; // AdminUserService, AdminProductService using Webshop.Domain.Interfaces; // IProductRepository using Webshop.Infrastructure.Data; // ApplicationDbContext using Webshop.Infrastructure.Repositories; // ProductRepository using Microsoft.AspNetCore.HttpOverrides; // For UseForwardedHeaders using Microsoft.Extensions.Logging; // For ILogger using Microsoft.OpenApi.Models; // For Swagger OpenAPI models using Webshop.Api.SwaggerFilters; // For AuthorizeOperationFilter var builder = WebApplication.CreateBuilder(args); // --- START: DIENSTE ZUM CONTAINER HINZUFÜGEN --- // 1. Datenbank-Kontext (DbContext) registrieren builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")) ); // 2. ASP.NET Core Identity für Benutzerverwaltung registrieren builder.Services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders(); // Optional: Passe die Anforderungen für Passwörter für die Entwicklung an builder.Services.Configure(options => { options.Password.RequireDigit = false; options.Password.RequiredLength = 6; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequireLowercase = false; options.SignIn.RequireConfirmedEmail = false; // Für einfache Entwicklung/Tests }); // 3. JWT-Authentifizierung konfigurieren var jwtSettings = builder.Configuration.GetSection("JwtSettings"); var secretKey = jwtSettings["Secret"] ?? throw new InvalidOperationException("JWT Secret not found in configuration."); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSettings["Issuer"], ValidAudience = jwtSettings["Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)) }; }); builder.Services.AddAuthorization(); // Aktiviert die Autorisierung // 4. Unsere eigenen Interfaces und Klassen registrieren (Dependency Injection) builder.Services.AddScoped(); // AUTH Services builder.Services.AddScoped(); // PUBLIC Services builder.Services.AddScoped(); // Ihr ProductService ist hier registriert // ADMIN Services builder.Services.AddScoped(); builder.Services.AddScoped(); // CUSTOMER Services (später Implementierungen hinzufügen) // builder.Services.AddScoped(); // 5. Controller und Swagger/OpenAPI hinzufügen builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { // 1. JWT Security Definition hinzufügen c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, // Der Token wird im Header gesendet Type = SecuritySchemeType.Http, // Dies ist ein HTTP-Schema Scheme = "Bearer" // Das Schema ist "Bearer" }); // 2. Security Requirement für alle Operationen hinzufügen c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" // Verweist auf die oben definierte "Bearer" Sicherheit } }, new string[] {} // Keine spezifischen "Scopes" für JWT (leer lassen) } }); // 3. Optional: Filtern und Anzeigen von Autorisierungsinformationen (Rollen) // Damit Swagger die "Authorize"-Informationen von Ihren Controllern anzeigt. c.OperationFilter(); }); // --- ENDE: DIENSTE ZUM CONTAINER HINZUFÜGEN --- var app = builder.Build(); // <-- Hier wird die App gebaut // OPTIONALE BLÖCKE FÜR MIGRATION UND BENUTZERINITIALISIERUNG - DIESER CODE WIRD VOR APP.RUN() AUSGEFÜHRT using (var scope = app.Services.CreateScope()) { var services = scope.ServiceProvider; try { var context = services.GetRequiredService(); // Wendet ausstehende Datenbank-Migrationen an (sehr nützlich für Entwicklung/Tests) context.Database.Migrate(); // --- TEMPORÄRER INITIALER ADMIN- UND KUNDEN-SETUP (NUR FÜR ERSTE ENTWICKLUNG!) --- // Dieser Block erstellt Rollen und initiale Benutzer, falls sie noch nicht existieren. // BITTE ENTFERNEN ODER KOMMENTIEREN SIE DIESEN BLOCK AUS, NACHDEM SIE IHRE ERSTEN BENUTZER ERSTELLT HABEN! var roleManager = services.GetRequiredService>(); var userManager = services.GetRequiredService>(); string[] roleNames = { "Admin", "Customer" }; foreach (var roleName in roleNames) { var roleExist = await roleManager.RoleExistsAsync(roleName); if (!roleExist) { await roleManager.CreateAsync(new IdentityRole(roleName)); } } // Erstelle einen initialen Admin-Benutzer var adminUser = await userManager.FindByEmailAsync("admin@yourwebshop.com"); // << ANPASSEN >> if (adminUser == null) { adminUser = new IdentityUser { UserName = "admin@yourwebshop.com", // << ANPASSEN >> Email = "admin@yourwebshop.com", // << ANPASSEN >> EmailConfirmed = true }; var createAdmin = await userManager.CreateAsync(adminUser, "SecureAdminPass123!"); // << ANPASSEN >> if (createAdmin.Succeeded) { await userManager.AddToRoleAsync(adminUser, "Admin"); Console.WriteLine("Admin user created."); } else { Console.WriteLine($"Error creating admin user: {string.Join(", ", createAdmin.Errors.Select(e => e.Description))}"); } } // Erstelle einen initialen Kunden-Benutzer var customerUser = await userManager.FindByEmailAsync("customer@yourwebshop.com"); // << ANPASSEN >> if (customerUser == null) { customerUser = new IdentityUser { UserName = "customer@yourwebshop.com", // << ANPASSEN >> Email = "customer@yourwebshop.com", // << ANPASSEN >> EmailConfirmed = true }; var createCustomer = await userManager.CreateAsync(customerUser, "SecureCustomerPass123!"); // << ANPASSEN >> if (createCustomer.Succeeded) { await userManager.AddToRoleAsync(customerUser, "Customer"); Console.WriteLine("Customer user created."); } else { Console.WriteLine($"Error creating customer user: {string.Join(", ", createCustomer.Errors.Select(e => e.Description))}"); } } // --- ENDE DES TEMPORÄREN SETUP-BLOCKS --- } catch (Exception ex) { var logger = services.GetRequiredService>(); logger.LogError(ex, "An error occurred during database migration or user initialization."); } } // <-- Hier endet der using-Scope // --- START: HTTP REQUEST PIPELINE KONFIGURIEREN --- // Middleware für Forwarded Headers (wichtig bei Reverse-Proxies wie Nginx oder Load Balancern) app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); // Swagger/SwaggerUI für API-Dokumentation aktivieren // Für die Produktion wäre es sicherer, dies an `app.Environment.IsDevelopment()` zu binden // if (app.Environment.IsDevelopment()) // { app.UseSwagger(); app.UseSwaggerUI(); // } // app.UseHttpsRedirection(); // Auskommentiert für Docker HTTP-Entwicklung (da der Proxy HTTPS übernimmt) // WICHTIG: Die Reihenfolge der Middleware ist entscheidend! app.UseAuthentication(); // Zuerst prüfen, wer der Benutzer ist app.UseAuthorization(); // Dann prüfen, was der Benutzer darf app.MapControllers(); // Stellt sicher, dass Ihre Controller als Endpunkte gemappt werden // --- ENDE: HTTP REQUEST PIPELINE KONFIGURIEREN --- app.Run(); // Hier startet die Anwendung und blockiert die weitere Ausführung