106 lines
3.5 KiB
C#
106 lines
3.5 KiB
C#
using System.Security.Claims;
|
|
using lxc_songlist.Components;
|
|
using lxc_songlist.Data;
|
|
using lxc_songlist.Services;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using MudBlazor.Services;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Add services to the container.
|
|
builder.Services.AddRazorComponents()
|
|
.AddInteractiveServerComponents();
|
|
builder.Services.AddCascadingAuthenticationState();
|
|
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
|
.AddCookie(options =>
|
|
{
|
|
options.LoginPath = "/admin/login";
|
|
options.AccessDeniedPath = "/admin/login";
|
|
options.Cookie.Name = "lxc-songlist-admin";
|
|
options.SlidingExpiration = true;
|
|
});
|
|
builder.Services.AddAuthorization();
|
|
builder.Services.AddMudServices();
|
|
|
|
builder.Services.Configure<AdminAuthOptions>(builder.Configuration.GetSection("Admin"));
|
|
builder.Services.Configure<SiteOptions>(builder.Configuration.GetSection("Site"));
|
|
|
|
builder.Services.AddDbContextFactory<SongListDbContext>(options =>
|
|
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
|
|
builder.Services.AddScoped<SongCatalogService>();
|
|
builder.Services.AddScoped<SiteSettingsService>();
|
|
builder.Services.AddSingleton<AdminPasswordService>();
|
|
|
|
var app = builder.Build();
|
|
|
|
// Configure the HTTP request pipeline.
|
|
if (!app.Environment.IsDevelopment())
|
|
{
|
|
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
|
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
|
app.UseHsts();
|
|
}
|
|
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
|
|
app.UseHttpsRedirection();
|
|
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
app.UseAntiforgery();
|
|
|
|
app.MapStaticAssets();
|
|
app.MapPost("/admin/sign-in", async (
|
|
HttpContext httpContext,
|
|
AdminPasswordService passwordService) =>
|
|
{
|
|
var form = await httpContext.Request.ReadFormAsync();
|
|
var password = form["password"].ToString();
|
|
var returnUrl = form["returnUrl"].ToString();
|
|
|
|
if (!passwordService.Verify(password))
|
|
{
|
|
return Results.Redirect("/admin/login?error=1");
|
|
}
|
|
|
|
var claims = new[]
|
|
{
|
|
new Claim(ClaimTypes.Name, "admin"),
|
|
new Claim(ClaimTypes.Role, "Admin")
|
|
};
|
|
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
|
|
var principal = new ClaimsPrincipal(identity);
|
|
|
|
await httpContext.SignInAsync(
|
|
CookieAuthenticationDefaults.AuthenticationScheme,
|
|
principal,
|
|
new AuthenticationProperties
|
|
{
|
|
IsPersistent = true,
|
|
ExpiresUtc = DateTimeOffset.UtcNow.AddDays(14)
|
|
});
|
|
|
|
return Results.Redirect(IsLocalUrl(returnUrl) ? returnUrl : "/admin");
|
|
})
|
|
.DisableAntiforgery();
|
|
|
|
app.MapGet("/admin/logout", async (HttpContext httpContext) =>
|
|
{
|
|
await httpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
|
return Results.Redirect("/");
|
|
})
|
|
.RequireAuthorization();
|
|
|
|
app.MapRazorComponents<App>()
|
|
.AddInteractiveServerRenderMode();
|
|
|
|
app.Run();
|
|
|
|
static bool IsLocalUrl(string? url)
|
|
{
|
|
return !string.IsNullOrWhiteSpace(url)
|
|
&& Uri.TryCreate(url, UriKind.Relative, out _)
|
|
&& url[0] == '/'
|
|
&& (url.Length == 1 || (url[1] != '/' && url[1] != '\\'));
|
|
}
|