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.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Watcher.ViewModels;
namespace Watcher.Controllers;
public class AuthController : Controller
{
private readonly IConfiguration _config;
public AuthController(IConfiguration config)
public IActionResult Login()
{
_config = config;
return View();
}
[HttpGet]
public IActionResult Login(string? returnUrl = null)
public IActionResult SignIn()
{
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
{
RedirectUri = redirectUrl
RedirectUri = "/"
}, "oidc");
}
[HttpGet]
public IActionResult ExternalLoginCallback(string? returnUrl = null)
{
return Redirect(returnUrl ?? "/");
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
[ValidateAntiForgeryToken]
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);
return RedirectToAction("Index", "Home");
}
RedirectUri = "/" // Nach Logout zurück zur Startseite oder Login-Seite
});
return RedirectToAction("Index", "Home");
}
[Authorize]
public IActionResult Info()

View File

@@ -55,67 +55,78 @@ builder.Services.AddDbContext<AppDbContext>((serviceProvider, options) =>
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
options.DefaultChallengeScheme = "Cookies"; // Nur wenn kein OIDC erzwungen wird
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
.AddCookie("Cookies", options =>
{
var config = builder.Configuration.GetSection("Authentication:PocketID");
options.Authority = config["Authority"];
options.ClientId = config["ClientId"];
options.ClientSecret = config["ClientSecret"];
options.ResponseType = "code";
options.CallbackPath = config["CallbackPath"];
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = async ctx =>
{
var db = ctx.HttpContext.RequestServices.GetRequiredService<AppDbContext>();
var principal = ctx.Principal;
var pocketId = principal.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;
var preferredUsername = principal.FindFirst("preferred_username")?.Value;
var email = principal.FindFirst("email")?.Value;
if (string.IsNullOrEmpty(pocketId))
return;
var user = await db.Users.FirstOrDefaultAsync(u => u.PocketId == pocketId);
if (user == null)
{
user = new User
{
PocketId = pocketId,
PreferredUsername = preferredUsername ?? "",
Email = email,
LastLogin = DateTime.UtcNow
};
db.Users.Add(user);
}
else
{
user.LastLogin = DateTime.UtcNow;
user.PreferredUsername = preferredUsername ?? user.PreferredUsername;
user.Email = email ?? user.Email;
db.Users.Update(user);
}
await db.SaveChangesAsync();
}
};
options.LoginPath = "/Account/Login"; // Falls eigene Login-Seite
});
// 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.CallbackPath = pocketIdSection["CallbackPath"];
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = async ctx =>
{
var db = ctx.HttpContext.RequestServices.GetRequiredService<AppDbContext>();
var principal = ctx.Principal;
var pocketId = principal.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;
var preferredUsername = principal.FindFirst("preferred_username")?.Value;
var email = principal.FindFirst("email")?.Value;
if (string.IsNullOrEmpty(pocketId))
return;
var user = await db.Users.FirstOrDefaultAsync(u => u.PocketId == pocketId);
if (user == null)
{
user = new User
{
PocketId = pocketId,
PreferredUsername = preferredUsername ?? "",
Email = email,
LastLogin = DateTime.UtcNow
};
db.Users.Add(user);
}
else
{
user.LastLogin = DateTime.UtcNow;
user.PreferredUsername = preferredUsername ?? user.PreferredUsername;
user.Email = email ?? user.Email;
db.Users.Update(user);
}
await db.SaveChangesAsync();
}
};
});
}
var app = builder.Build();
@@ -145,7 +156,7 @@ app.UseStaticFiles();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
pattern: "{controller=Auth}/{action=Login}/"
);

View File

@@ -1,36 +1,28 @@
@model Watcher.ViewModels.LoginViewModel
@{
ViewData["Title"] = "Login";
}
<h2>Anmelden</h2>
<div class="login-container">
<h2>Login</h2>
<form asp-action="Login" method="post">
<div class="form-group">
<label asp-for="Username"></label>
<input asp-for="Username" class="form-control" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<form asp-action="Login" method="post">
<div>
<label asp-for="Username"></label>
<input asp-for="Username" />
<span asp-validation-for="Username"></span>
</div>
<div>
<label asp-for="Password"></label>
<input asp-for="Password" type="password" />
<span asp-validation-for="Password"></span>
</div>
<button type="submit">Login</button>
</form>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" type="password" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<hr />
<input type="hidden" asp-for="ReturnUrl" />
<button type="submit" class="btn btn-primary">Anmelden</button>
</form>
<hr />
<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" />
}
<form asp-controller="Auth" asp-action="SignIn" method="get">
<button type="submit">Mit PocketID anmelden</button>
</form>
</div>

View File

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

View File

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