This commit is contained in:
parent
325e2f1ee9
commit
08e573d63c
17 changed files with 348 additions and 26 deletions
88
Program.cs
88
Program.cs
|
|
@ -1,6 +1,7 @@
|
|||
using System.Globalization;
|
||||
using System.Security.Claims;
|
||||
using NLog.Web;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
|
|
@ -25,18 +26,32 @@ builder.Host.UseNLog();
|
|||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
|
||||
builder.Services.Configure<AppAuthOptions>(builder.Configuration.GetSection(AppAuthOptions.SectionName));
|
||||
var appAuthOptions = builder.Configuration.GetSection(AppAuthOptions.SectionName).Get<AppAuthOptions>() ?? new AppAuthOptions();
|
||||
var authenticationEnabled = appAuthOptions.Enabled;
|
||||
|
||||
builder.Services.AddCascadingAuthenticationState();
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.LoginPath = "/login";
|
||||
options.LogoutPath = "/logout";
|
||||
options.AccessDeniedPath = "/login";
|
||||
options.SlidingExpiration = true;
|
||||
options.ExpireTimeSpan = TimeSpan.FromDays(14);
|
||||
});
|
||||
if (authenticationEnabled)
|
||||
{
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.LoginPath = "/login";
|
||||
options.LogoutPath = "/logout";
|
||||
options.AccessDeniedPath = "/login";
|
||||
options.SlidingExpiration = true;
|
||||
options.ExpireTimeSpan = TimeSpan.FromDays(14);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Services.AddAuthentication(DefaultAdminAuthenticationHandler.SchemeName)
|
||||
.AddScheme<AuthenticationSchemeOptions, DefaultAdminAuthenticationHandler>(
|
||||
DefaultAdminAuthenticationHandler.SchemeName,
|
||||
static _ => { });
|
||||
}
|
||||
|
||||
builder.Services.AddLocalization();
|
||||
|
||||
|
|
@ -86,14 +101,29 @@ app.UseAuthorization();
|
|||
|
||||
app.UseAntiforgery();
|
||||
|
||||
static string GetSafeReturnUrl(string? returnUrl)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(returnUrl) || !Uri.IsWellFormedUriString(returnUrl, UriKind.Relative)
|
||||
? "/"
|
||||
: returnUrl;
|
||||
}
|
||||
|
||||
app.MapPost("/api/login", async (HttpContext context) =>
|
||||
{
|
||||
var form = await context.Request.ReadFormAsync();
|
||||
var returnUrl = form["returnUrl"].ToString();
|
||||
var safeReturnUrl = GetSafeReturnUrl(returnUrl);
|
||||
|
||||
if (!authenticationEnabled)
|
||||
{
|
||||
context.Response.Redirect(safeReturnUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
var authService = context.RequestServices.GetRequiredService<IAuthService>();
|
||||
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger("Auth.Login");
|
||||
var form = await context.Request.ReadFormAsync();
|
||||
var username = form["username"].ToString();
|
||||
var password = form["password"].ToString();
|
||||
var returnUrl = form["returnUrl"].ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
|
|
@ -125,16 +155,18 @@ app.MapPost("/api/login", async (HttpContext context) =>
|
|||
return;
|
||||
}
|
||||
|
||||
var safeReturnUrl = string.IsNullOrWhiteSpace(returnUrl) || !Uri.IsWellFormedUriString(returnUrl, UriKind.Relative)
|
||||
? "/"
|
||||
: returnUrl;
|
||||
|
||||
context.Response.Redirect(safeReturnUrl);
|
||||
return;
|
||||
}).DisableAntiforgery();
|
||||
|
||||
app.MapPost("/api/logout", async (HttpContext context) =>
|
||||
{
|
||||
if (!authenticationEnabled)
|
||||
{
|
||||
context.Response.Redirect("/");
|
||||
return;
|
||||
}
|
||||
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
context.Response.Redirect("/login");
|
||||
return;
|
||||
|
|
@ -142,6 +174,12 @@ app.MapPost("/api/logout", async (HttpContext context) =>
|
|||
|
||||
app.MapPost("/api/change-password", async (HttpContext context) =>
|
||||
{
|
||||
if (!authenticationEnabled)
|
||||
{
|
||||
context.Response.Redirect("/");
|
||||
return;
|
||||
}
|
||||
|
||||
var authService = context.RequestServices.GetRequiredService<IAuthService>();
|
||||
if (!context.User?.Identity?.IsAuthenticated ?? true)
|
||||
{
|
||||
|
|
@ -159,7 +197,7 @@ app.MapPost("/api/change-password", async (HttpContext context) =>
|
|||
return;
|
||||
}
|
||||
|
||||
var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
var userId = context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
if (string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
await context.ChallengeAsync();
|
||||
|
|
@ -177,6 +215,24 @@ app.MapPost("/api/change-password", async (HttpContext context) =>
|
|||
return;
|
||||
}).DisableAntiforgery();
|
||||
|
||||
app.MapGet("/healthz", [AllowAnonymous] (HttpContext context, IOptions<AppAuthOptions> authOptions, CouchbaseLiteDatabaseProvider databaseProvider) =>
|
||||
{
|
||||
return Results.Json(new
|
||||
{
|
||||
status = "Healthy",
|
||||
authenticationEnabled = authOptions.Value.Enabled,
|
||||
currentUser = context.User.Identity?.Name,
|
||||
environment = app.Environment.EnvironmentName,
|
||||
storage = new
|
||||
{
|
||||
appSettingsReady = databaseProvider.AppSettings is not null,
|
||||
usersReady = databaseProvider.Users is not null,
|
||||
workDaysReady = databaseProvider.WorkDays is not null
|
||||
},
|
||||
timestampUtc = DateTimeOffset.UtcNow
|
||||
});
|
||||
});
|
||||
|
||||
// Development-only endpoint to reset the seeded Admin password (protected by secret in URL)
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue