Login Logik aktualisiert

This commit is contained in:
2025-06-17 19:29:41 +02:00
parent dd334c2dad
commit 362dee0c83
5 changed files with 109 additions and 146 deletions

View File

@@ -1,80 +1,39 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Watcher.ViewModels;
namespace Watcher.Controllers; namespace Watcher.Controllers;
public class AuthController : Controller public class AuthController : Controller
{ {
private readonly IConfiguration _config; public IActionResult Login()
public AuthController(IConfiguration config)
{ {
_config = config; return View();
} }
[HttpGet] public IActionResult SignIn()
public IActionResult Login(string? returnUrl = null)
{ {
var vm = new LoginViewModel { ReturnUrl = returnUrl };
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (!ModelState.IsValid)
return View(model);
// Beispielhafte, harte lokale Benutzerprüfung
if (model.Username == "admin" && model.Password == "password")
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, model.Username),
new Claim(ClaimTypes.Role, "Admin")
};
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
return Redirect(model.ReturnUrl ?? "/");
}
ModelState.AddModelError("", "Ungültiger Benutzername oder Passwort");
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult SignIn(string? returnUrl = null)
{
var redirectUrl = Url.Action(nameof(ExternalLoginCallback), "Auth", new { returnUrl });
return Challenge(new AuthenticationProperties return Challenge(new AuthenticationProperties
{ {
RedirectUri = redirectUrl RedirectUri = "/"
}, "oidc"); }, "oidc");
} }
[HttpGet]
public IActionResult ExternalLoginCallback(string? returnUrl = null)
{
return Redirect(returnUrl ?? "/");
}
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public async Task<IActionResult> Logout() public async Task<IActionResult> Logout()
{
// Lokales Cookie löschen
await HttpContext.SignOutAsync("Cookies");
// Externes OIDC-Logout initiieren
await HttpContext.SignOutAsync("oidc", new AuthenticationProperties
{ {
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); RedirectUri = "/" // Nach Logout zurück zur Startseite oder Login-Seite
});
return RedirectToAction("Index", "Home"); return RedirectToAction("Index", "Home");
} }
[Authorize] [Authorize]
public IActionResult Info() public IActionResult Info()

View File

@@ -55,17 +55,27 @@ builder.Services.AddDbContext<AppDbContext>((serviceProvider, options) =>
builder.Services.AddAuthentication(options => builder.Services.AddAuthentication(options =>
{ {
options.DefaultScheme = "Cookies"; options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc"; options.DefaultChallengeScheme = "Cookies"; // Nur wenn kein OIDC erzwungen wird
}) })
.AddCookie("Cookies") .AddCookie("Cookies", options =>
.AddOpenIdConnect("oidc", options =>
{ {
var config = builder.Configuration.GetSection("Authentication:PocketID"); options.LoginPath = "/Account/Login"; // Falls eigene Login-Seite
options.Authority = config["Authority"]; });
options.ClientId = config["ClientId"];
options.ClientSecret = config["ClientSecret"]; // PocketID nur konfigurieren, wenn aktiviert
var pocketIdSection = builder.Configuration.GetSection("Authentication:PocketID");
var pocketIdEnabled = pocketIdSection.GetValue<bool>("Enabled");
if (pocketIdEnabled)
{
builder.Services.AddAuthentication()
.AddOpenIdConnect("oidc", options =>
{
options.Authority = pocketIdSection["Authority"];
options.ClientId = pocketIdSection["ClientId"];
options.ClientSecret = pocketIdSection["ClientSecret"];
options.ResponseType = "code"; options.ResponseType = "code";
options.CallbackPath = config["CallbackPath"]; options.CallbackPath = pocketIdSection["CallbackPath"];
options.SaveTokens = true; options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true; options.GetClaimsFromUserInfoEndpoint = true;
@@ -76,7 +86,7 @@ builder.Services.AddAuthentication(options =>
options.Scope.Add("email"); options.Scope.Add("email");
options.Events = new OpenIdConnectEvents options.Events = new OpenIdConnectEvents
{ {
OnTokenValidated = async ctx => OnTokenValidated = async ctx =>
{ {
var db = ctx.HttpContext.RequestServices.GetRequiredService<AppDbContext>(); var db = ctx.HttpContext.RequestServices.GetRequiredService<AppDbContext>();
@@ -112,9 +122,10 @@ builder.Services.AddAuthentication(options =>
await db.SaveChangesAsync(); await db.SaveChangesAsync();
} }
}; };
});
}
});
var app = builder.Build(); var app = builder.Build();
@@ -145,7 +156,7 @@ app.UseStaticFiles();
app.MapControllerRoute( app.MapControllerRoute(
name: "default", name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}" pattern: "{controller=Auth}/{action=Login}/"
); );

View File

@@ -1,36 +1,28 @@
@model Watcher.ViewModels.LoginViewModel @model Watcher.ViewModels.LoginViewModel
@{ @{
ViewData["Title"] = "Login"; ViewData["Title"] = "Login";
} }
<h2>Anmelden</h2> <div class="login-container">
<h2>Login</h2>
<form asp-action="Login" method="post"> <form asp-action="Login" method="post">
<div class="form-group"> <div>
<label asp-for="Username"></label> <label asp-for="Username"></label>
<input asp-for="Username" class="form-control" /> <input asp-for="Username" />
<span asp-validation-for="Username" class="text-danger"></span> <span asp-validation-for="Username"></span>
</div> </div>
<div>
<div class="form-group">
<label asp-for="Password"></label> <label asp-for="Password"></label>
<input asp-for="Password" class="form-control" type="password" /> <input asp-for="Password" type="password" />
<span asp-validation-for="Password" class="text-danger"></span> <span asp-validation-for="Password"></span>
</div> </div>
<button type="submit">Login</button>
</form>
<input type="hidden" asp-for="ReturnUrl" /> <hr />
<button type="submit" class="btn btn-primary">Anmelden</button> <form asp-controller="Auth" asp-action="SignIn" method="get">
</form> <button type="submit">Mit PocketID anmelden</button>
</form>
<hr /> </div>
<form asp-action="LoginWithOidc" method="post">
<input type="hidden" name="returnUrl" value="@Model.ReturnUrl" />
<button type="submit" class="btn btn-outline-secondary">Mit PocketID anmelden</button>
</form>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@@ -62,10 +62,10 @@
<h4>Watcher</h4> <h4>Watcher</h4>
<ul class="nav flex-column"> <ul class="nav flex-column">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/">Dashboard</a> <a class="nav-link" href="/Home/Index">Dashboard</a>
</li> </li>
<li class="nav-item"></li> <li class="nav-item"></li>
<a class="nav-link" href="/Uptime">Uptime</a> <a class="nav-link" href="/Uptime/Overview">Uptime</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/Server/Overview">Servers</a> <a class="nav-link" href="/Server/Overview">Servers</a>

View File

@@ -18,6 +18,7 @@
"Authentication": { "Authentication": {
"UseLocal": true, "UseLocal": true,
"PocketIDEnabled": true,
"PocketID": { "PocketID": {
"Authority": "https://pocketid.triggermeelmo.com", "Authority": "https://pocketid.triggermeelmo.com",
"ClientId": "629a5f42-ab02-4905-8311-cc7b64165cc0", "ClientId": "629a5f42-ab02-4905-8311-cc7b64165cc0",