diff --git a/Components/Pages/Books.razor b/Components/Pages/Books.razor
index 46e9590..795cac9 100644
--- a/Components/Pages/Books.razor
+++ b/Components/Pages/Books.razor
@@ -1,4 +1,5 @@
@page "/books"
+@attribute [Microsoft.AspNetCore.Authorization.Authorize]
@using SecDevOpsLab.Models
@using SecDevOpsLab.Data
@inject AppDbContext Db
diff --git a/Components/Pages/Login.razor b/Components/Pages/Login.razor
new file mode 100644
index 0000000..fc10951
--- /dev/null
+++ b/Components/Pages/Login.razor
@@ -0,0 +1,39 @@
+@page "/login"
+@using System.Security.Claims
+@using Microsoft.AspNetCore.Authentication
+@using Microsoft.AspNetCore.Authentication.Cookies
+@inject NavigationManager Navigation
+
+
SecDevOps Lab Login
+
+@if (!string.IsNullOrEmpty(errorMessage))
+{
+ @errorMessage
+}
+
+@* Wichtig: Ein traditionelles HTML-Formular nutzen, um Cookies setzen zu können *@
+
+
+@code {
+ private string? errorMessage;
+
+ protected override void OnInitialized()
+ {
+ // Falls ein Fehler beim Login auftrat, fangen wir ihn über die URL ab
+ var uri = Navigation.ToAbsoluteUri(Navigation.Uri);
+ if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("error", out var error))
+ {
+ errorMessage = "Ungültige Zugangsdaten.";
+ }
+ }
+}
diff --git a/Program.cs b/Program.cs
index 24f080b..9cced66 100644
--- a/Program.cs
+++ b/Program.cs
@@ -3,10 +3,29 @@ using Microsoft.EntityFrameworkCore;
// Importieren der Klassen
using SecDevOpsLab.Data;
using SecDevOpsLab.Components;
+// NEU: Namespaces für Authentifizierung und Routing hinzufügen
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.AspNetCore.Components.Server;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Mvc;
// Initialisieren des Web Builders, der den Server und die Umgebung vorbereitet
var builder = WebApplication.CreateBuilder(args);
+// NEU: Blazor-Authentifizierungsdienste registrieren
+builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
+ .AddCookie(options =>
+ {
+ options.LoginPath = "/login"; // Wohin unberechtigte Nutzer geleitet werden
+ options.ExpireTimeSpan = TimeSpan.FromHours(2);
+ });
+
+// NEU: Erlaubt Blazor-Komponenten, den Login-Status abzufragen
+builder.Services.AddCascadingAuthenticationState();
+builder.Services.AddScoped();
+
// Hinzufügen des Blazor Service und die Interagierbarkeit des Frontends
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
@@ -36,6 +55,11 @@ if (!app.Environment.IsDevelopment())
// Erlauben des Zugriffs auf wwwroot Dir
app.UseStaticFiles();
+
+// NEU: Authentifizierungs-Middleware aktivieren (MUSS vor Antiforgery stehen!)
+app.UseAuthentication();
+app.UseAuthorization();
+
// Schützen vor CSRF Attacken
app.UseAntiforgery();
@@ -43,5 +67,30 @@ app.UseAntiforgery();
app.MapRazorComponents()
.AddInteractiveServerRenderMode();
+// ==========================================
+// SCHRITT 3: HIER EINGEFÜGT (Login-Endpunkt)
+// ==========================================
+app.MapPost("/api/auth/login", async (
+ [FromForm] string username,
+ [FromForm] string password,
+ HttpContext httpContext) =>
+{
+ // Statischer User (Für SecDevOps später via Environment Variable aus K8s-Secret laden!)
+ const string StaticUser = "admin";
+ const string StaticPassword = "DevOpsPassword2026!";
+
+ if (username == StaticUser && password == StaticPassword)
+ {
+ var claims = new List { new Claim(ClaimTypes.Name, username) };
+ var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
+
+ await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
+
+ return Results.Redirect("/"); // Erfolgreich eingeloggt -> zur Startseite
+ }
+
+ return Results.Redirect("/login?error=true"); // Fehler -> zurück zum Login
+});
+
// Webserver wird gestartet. Port 8080 wird eröffnet
app.Run();