1
0
Kevin Matsubara b65d998b01 Add policy authorization based on claim for admin role.
Note that this redirects to the login page, it should actually display an Access Denied message.
2025-04-18 17:53:20 +02:00

98 lines
3.8 KiB
C#

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using ServerManagement.Components;
using ServerManagement.Components.Account;
using ServerManagement.Data;
using ServerManagement.Models;
using ServerManagement.StateStore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Do not use this, it can cause non-thread-safe complications, due to its Scoped lifetime.
// builder.Services.AddDbContext<ServerManagementContext>();
// Instead, use factory:
builder.Services.AddDbContextFactory<ServerManagementContext>(
options => {
options.UseSqlite(builder.Configuration.GetConnectionString("ServerManagement"));
}
);
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(); // Provides server interactivity.
// Singleton - A single instance is created and shared troughout the application's lifetime.
// Scoped - A new instance is created for each request.
// Transient - A new instance is created every time it is needed.
// See: https://www.youtube.com/watch?v=V-8HlozCTOU
builder.Services.AddTransient<SessionStorage>();
// Scoped lifespan is the same as the SignalR lifespan.
// Everything stored in the SignalR channel will be lost if that connection is broken.
// This means that the data in there, can only be used for the current user.
// For a WebAssembly, you want to use AddSingleton, so that everything is locally downloaded in the browser.
builder.Services.AddScoped<ContainerStorage>();
builder.Services.AddScoped<EindhovenOnlineServersStore>();
// Transient is used here, the database is already globally accessible,
// so this service does not need to live longer than necessary, just when needed.
// First the interface is registered, then its concrete implementation.
builder.Services.AddTransient<IServersEFCoreRepository, ServersEFCoreRepository>();
// Add Identity services.
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IdentityUserAccessor>();
builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("Administrator", policy => policy.RequireClaim("Role", "Admin"));
}
);
var connectionString = builder.Configuration.GetConnectionString("ServerManagement") ?? throw new InvalidOperationException("Connection string 'ServerManagement' not found.");
builder.Services.AddDbContext<IdentityContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<IdentityContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(); // Provides server interactivity.
// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();
app.Run();