From 4f8197c500700d4083b0c07a2d6617075ee488c2 Mon Sep 17 00:00:00 2001 From: daniel-hbn Date: Wed, 25 Jun 2025 18:01:03 +0200 Subject: [PATCH] =?UTF-8?q?Serilog=20konfiguriert=20und=20Code=20in=20Hear?= =?UTF-8?q?tbeat-=20Home-=20und=20Auth-Controller=20aufr=C3=A4umen=20gesta?= =?UTF-8?q?rtet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- Watcher/Controllers/AuthController.cs | 41 +++++++++++++++++----- Watcher/Controllers/HeartbeatController.cs | 18 +++++++--- Watcher/Controllers/HomeController.cs | 21 ++++++++--- Watcher/Program.cs | 40 ++++++++++++++------- Watcher/Views/Home/Index.cshtml | 1 + Watcher/Watcher.csproj | 2 ++ 7 files changed, 93 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index ff87601..8e2b702 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Per-Use special Files and Directories /persistance/*.db -/logs +/logs/*.log *.env /wwwroot/downloads/sqlite/*.sql diff --git a/Watcher/Controllers/AuthController.cs b/Watcher/Controllers/AuthController.cs index 5cf652e..91feb88 100644 --- a/Watcher/Controllers/AuthController.cs +++ b/Watcher/Controllers/AuthController.cs @@ -22,12 +22,19 @@ public class AuthController : Controller private readonly AppDbContext _context; private readonly AppSettings _settings; - public AuthController(AppDbContext context, IOptions options) + // Logging einbinden + private readonly ILogger _logger; + + + public AuthController(AppDbContext context, IOptions options, ILogger logger) { _context = context; _settings = options.Value; + _logger = logger; } + + // Login Seite anzeigen [HttpGet] public IActionResult Login(string? returnUrl = null) { @@ -41,6 +48,7 @@ public class AuthController : Controller } + // Login mit lokalem User [HttpPost] public async Task Login(LoginViewModel model) { @@ -55,20 +63,23 @@ public class AuthController : Controller } var claims = new List - { - new Claim(ClaimTypes.Name, user.Username), - new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), - }; + { + new Claim(ClaimTypes.Name, user.Username), + new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), + }; var identity = new ClaimsIdentity(claims, "local"); var principal = new ClaimsPrincipal(identity); await HttpContext.SignInAsync("Cookies", principal); + _logger.LogInformation("lokaler User angemeldet: " + user.Username); + return Redirect("Home/Index"); } + // Login mit OIDC-Provider public IActionResult SignIn() { return Challenge(new AuthenticationProperties @@ -77,6 +88,9 @@ public class AuthController : Controller }, "oidc"); } + + + // Logout [HttpPost] [ValidateAntiForgeryToken] public async Task Logout() @@ -89,26 +103,32 @@ public class AuthController : Controller await HttpContext.SignOutAsync("Cookies"); await HttpContext.SignOutAsync("oidc", props); + _logger.LogInformation("User abgemeldet"); + return Redirect("/"); // nur als Fallback } + + // Anzeigen der User-Informationen [Authorize] public IActionResult Info() { - var username = User.Identity?.Name; - Console.WriteLine("gefundener User: " + username); var claims = User.Claims.Select(c => new { c.Type, c.Value }).ToList(); + var Identity_User = User.Identity?.Name; - var user = _context.Users.FirstOrDefault(u => u.Username == username); + var user = _context.Users.FirstOrDefault(u => u.Username == Identity_User); if (user == null) return NotFound(); + // Anzeigedaten var DbProvider = _context.Database.ProviderName; + var username = user.Username; var mail = user.Email; var Id = user.Id; - ViewBag.Name = username; + // Anzeigedaten an View übergeben ViewBag.Claims = claims; + ViewBag.Name = username; ViewBag.Mail = mail; ViewBag.Id = Id; @@ -154,9 +174,12 @@ public class AuthController : Controller // Eventuell hier das Auth-Cookie erneuern, wenn Username sich ändert + _logger.LogTrace("Passwort-Change durchgeführt"); + return RedirectToAction("Index", "Home"); } + // Edit-Form anzeigen [Authorize] [HttpGet] diff --git a/Watcher/Controllers/HeartbeatController.cs b/Watcher/Controllers/HeartbeatController.cs index 10015a9..1203b4f 100644 --- a/Watcher/Controllers/HeartbeatController.cs +++ b/Watcher/Controllers/HeartbeatController.cs @@ -1,13 +1,10 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis; using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; using Watcher.Data; using Watcher.Models; -using Watcher.ViewModels; +// eingehender Heartbeat-Payload public class HeartbeatDto { public string? IpAddress { get; set; } @@ -18,18 +15,27 @@ public class HeartbeatDto public class HeartbeatController : Controller { + // Datenbankverbindung private readonly AppDbContext _context; - public HeartbeatController(AppDbContext context) + // Logging einbinden + private readonly ILogger _logger; + + public HeartbeatController(AppDbContext context, ILogger logger) { _context = context; + _logger = logger; } + // Endpoint um Heartbeat-Payloads zu empfangen [HttpPost("receive")] public async Task Receive([FromBody] HeartbeatDto dto) { + _logger.LogInformation("Heartbeat empfangen"); + if (string.IsNullOrWhiteSpace(dto.IpAddress)) { + _logger.LogWarning("Eingehender Payload enthält keine IP-Adresse"); return BadRequest("Missing IP address."); } @@ -40,9 +46,11 @@ public class HeartbeatController : Controller { server.LastSeen = DateTime.UtcNow; await _context.SaveChangesAsync(); + _logger.LogInformation("Heartbeat von {server} in Datenbank eingetragen.", server.Name); return Ok(); } + _logger.LogWarning("Eingehender Payload kann keiner bekannten IP-Adresse zugewiesen werden."); return NotFound("No matching server found."); } } diff --git a/Watcher/Controllers/HomeController.cs b/Watcher/Controllers/HomeController.cs index aa64f6a..fd5043d 100644 --- a/Watcher/Controllers/HomeController.cs +++ b/Watcher/Controllers/HomeController.cs @@ -1,9 +1,9 @@ +// .NET Packages using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using System.Security.Claims; +// Local Namespaces using Watcher.Data; -using Watcher.Models; using Watcher.ViewModels; namespace Watcher.Controllers @@ -11,13 +11,20 @@ namespace Watcher.Controllers [Authorize] public class HomeController : Controller { + // Datenbankverbindung private readonly AppDbContext _context; - public HomeController(AppDbContext context) + // Logging einbinden + private readonly ILogger _logger; + + // HomeController Constructor + public HomeController(AppDbContext context, ILogger logger) { _context = context; + _logger = logger; } + // Dashboard unter /home/index public async Task Index() { var preferredUserName = User.FindFirst("preferred_username")?.Value; @@ -39,9 +46,10 @@ namespace Watcher.Controllers return View(viewModel); } + // Funktion für /Views/Home/Index.cshtml um das DashboardStats-Partial neu zu laden. + // Die Funktion wird nicht direkt aufgerufen, sondern nur der /Home/DashboardStats Endpoint angefragt. public IActionResult DashboardStats() { - Console.WriteLine("Dashboard aktualisiert"); var servers = _context.Servers.ToList(); var containers = _context.Containers.ToList(); @@ -51,9 +59,12 @@ namespace Watcher.Controllers { ActiveServers = servers.Count(s => (now - s.LastSeen).TotalSeconds <= 120), OfflineServers = servers.Count(s => (now - s.LastSeen).TotalSeconds > 120), + + //TODO: anwendbar, wenn Container implementiert wurden. //RunningContainers = containers.Count(c => (now - c.LastSeen).TotalSeconds <= 120), //FailedContainers = containers.Count(c => (now - c.LastSeen).TotalSeconds > 120), - LastLogin = DateTime.Now // Oder was auch immer hier richtig ist + + LastLogin = DateTime.Now }; return PartialView("_DashboardStats", model); diff --git a/Watcher/Program.cs b/Watcher/Program.cs index baba787..4356947 100644 --- a/Watcher/Program.cs +++ b/Watcher/Program.cs @@ -4,17 +4,39 @@ using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Sqlite; using Microsoft.IdentityModel.Tokens; + +using Serilog; + using Watcher.Data; using Watcher.Models; + var builder = WebApplication.CreateBuilder(args); + +// Serilog konfigurieren – nur Logs, die nicht von Microsoft stammen +Log.Logger = new LoggerConfiguration() + .MinimumLevel.Information() + .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning) // <-- + .Enrich.FromLogContext() + .WriteTo.File( + "logs/watcher-.log", + outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss}] [{Level:u3}] {Message:lj}{NewLine}{Exception}", + rollingInterval: RollingInterval.Day + ) + .CreateLogger(); + +builder.Host.UseSerilog(); + + // Add services to the container. builder.Services.AddControllersWithViews(); + // HttpContentAccessor builder.Services.AddHttpContextAccessor(); + // ---------- Konfiguration ---------- DotNetEnv.Env.Load(); @@ -22,14 +44,14 @@ builder.Configuration .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddEnvironmentVariables(); + // Konfiguration laden var configuration = builder.Configuration; -// ---------- DB-Kontext ---------- +// ---------- DB-Kontext ---------- var dbProvider = configuration["Database:Provider"] ?? "MySQL"; var connectionString = configuration["Database:ConnectionString"]; - builder.Services.AddDbContext((serviceProvider, options) => { var config = serviceProvider.GetRequiredService(); @@ -51,19 +73,21 @@ builder.Services.AddDbContext((serviceProvider, options) => } }); + // ---------- Authentifizierung konfigurieren ---------- // PocketID nur konfigurieren, wenn aktiviert var pocketIdSection = builder.Configuration.GetSection("Authentication:PocketID"); var pocketIdEnabled = pocketIdSection.GetValue("Enabled"); -var auth = builder.Services.AddAuthentication("Cookies"); +var auth = builder.Services.AddAuthentication("Cookies"); auth.AddCookie("Cookies", options => { options.LoginPath = "/Auth/Login"; options.AccessDeniedPath = "/Auth/AccessDenied"; }); + builder.Services.AddAuthentication() .AddOpenIdConnect("oidc", options => { @@ -124,12 +148,9 @@ builder.Services.AddAuthentication() }); - - var app = builder.Build(); - // Migrationen anwenden (für SQLite oder andere DBs) using (var scope = app.Services.CreateScope()) { @@ -169,6 +190,7 @@ using (var scope = app.Services.CreateScope()) } } + // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { @@ -178,10 +200,6 @@ if (!app.Environment.IsDevelopment()) } - - - - app.UseHttpsRedirection(); app.UseRouting(); @@ -190,11 +208,9 @@ app.UseAuthorization(); app.UseStaticFiles(); - app.MapControllerRoute( name: "default", pattern: "{controller=Auth}/{action=Login}/" ); - app.Run(); diff --git a/Watcher/Views/Home/Index.cshtml b/Watcher/Views/Home/Index.cshtml index 99ca8c5..08b7321 100644 --- a/Watcher/Views/Home/Index.cshtml +++ b/Watcher/Views/Home/Index.cshtml @@ -47,6 +47,7 @@ try { const response = await fetch('/Home/DashboardStats'); if (response.ok) { + console.log("reload") const html = await response.text(); document.getElementById('dashboard-stats').innerHTML = html; } else { diff --git a/Watcher/Watcher.csproj b/Watcher/Watcher.csproj index bad6c1b..f015024 100644 --- a/Watcher/Watcher.csproj +++ b/Watcher/Watcher.csproj @@ -20,6 +20,8 @@ + +