Login works now, as does logout

This commit is contained in:
Rhywden
2026-08-23 17:33:06 +02:00
parent 8f006ec568
commit c06e6c0e84
4 changed files with 126 additions and 4 deletions
@@ -6,6 +6,28 @@
<MudSnackbarProvider /> <MudSnackbarProvider />
<MudLayout> <MudLayout>
<MudAppBar>
<MudSpacer />
<AuthorizeView Context="authenticationState">
<Authorized>
@{
var user = authenticationState.User;
var displayName = string.Join(" ", new[]
{
user.FindFirst("given_name")?.Value,
user.FindFirst("family_name")?.Value
}.Where(value => !string.IsNullOrWhiteSpace(value)));
var classroom = user.FindFirst("classroom")?.Value
?? (user.IsInRole("ROLE_TEACHER") ? "Lehrer" : null);
}
<MudText>@displayName@(classroom is null ? string.Empty : $" ({classroom})")</MudText>
<form method="post" action="/logout">
<AntiforgeryToken />
<MudButton ButtonType="ButtonType.Submit" Color="Color.Inherit" Variant="Variant.Text">Logout</MudButton>
</form>
</Authorized>
</AuthorizeView>
</MudAppBar>
<MudMainContent> <MudMainContent>
@Body @Body
</MudMainContent> </MudMainContent>
+2 -1
View File
@@ -1,5 +1,6 @@
@using System.Net.Http @using System.Net.Http
@using System.Net.Http.Json @using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web
@@ -9,4 +10,4 @@
@using Wollmilchsau @using Wollmilchsau
@using Wollmilchsau.Components @using Wollmilchsau.Components
@using Wollmilchsau.Components.Layout @using Wollmilchsau.Components.Layout
@using MudBlazor @using MudBlazor
+100 -1
View File
@@ -1,14 +1,76 @@
using Fluxor; using Fluxor;
using JasperFx; using JasperFx;
using Marten; using Marten;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using MudBlazor.Services; using MudBlazor.Services;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Json;
using Wollmilchsau.Components; using Wollmilchsau.Components;
using Wollmilchsau.Exceptions; using Wollmilchsau.Exceptions;
using Wollmilchsau.Services.Ldap; using Wollmilchsau.Services.Ldap;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
var oidcConfiguration = builder.Configuration.GetRequiredSection("OIDC");
var oidcScopes = oidcConfiguration.GetSection("Scopes").Get<string[]>()
?? throw new ConfigurationException("OIDC:Scopes");
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = oidcConfiguration["Authority"] ?? throw new ConfigurationException("OIDC:Authority");
options.ClientId = oidcConfiguration["ClientId"] ?? throw new ConfigurationException("OIDC:ClientId");
options.ClientSecret = oidcConfiguration["ClientSecret"] ?? throw new ConfigurationException("OIDC:ClientSecret");
options.ResponseType = oidcConfiguration["ResponseType"] ?? throw new ConfigurationException("OIDC:ResponseType");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.MapInboundClaims = false;
options.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Disable;
options.Scope.Clear();
foreach (var scope in oidcScopes)
{
options.Scope.Add(scope);
}
options.Events.OnTokenValidated = context =>
{
AddUserClaims(
context.Principal?.Identity as ClaimsIdentity,
context.Principal?.FindAll("groups").Select(claim => claim.Value).ToArray() ?? [],
context.Principal?.FindFirst("klasse")?.Value);
return Task.CompletedTask;
};
options.Events.OnUserInformationReceived = context =>
{
var userInfo = context.User.RootElement;
var groups = userInfo.TryGetProperty("groups", out var groupsElement) && groupsElement.ValueKind == JsonValueKind.Array
? groupsElement.EnumerateArray()
.Where(group => group.ValueKind == JsonValueKind.String)
.Select(group => group.GetString())
.OfType<string>()
: [];
var classroom = userInfo.TryGetProperty("klasse", out var classroomElement) && classroomElement.ValueKind == JsonValueKind.String
? classroomElement.GetString()
: null;
AddUserClaims(context.Principal?.Identity as ClaimsIdentity, groups, classroom);
return Task.CompletedTask;
};
});
builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddOptions<LdapOptions>() builder.Services.AddOptions<LdapOptions>()
.BindConfiguration("LDAP") .BindConfiguration("LDAP")
.ValidateDataAnnotations() .ValidateDataAnnotations()
@@ -70,10 +132,47 @@ if (!app.Environment.IsDevelopment())
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true); app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery(); app.UseAntiforgery();
app.MapStaticAssets(); app.MapStaticAssets();
app.MapPost("/logout", async (HttpContext context) =>
{
var authenticationResult = await context.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
var properties = authenticationResult.Properties ?? new AuthenticationProperties();
properties.RedirectUri = "/";
return Results.SignOut(
properties,
[CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme]);
})
.RequireAuthorization()
.WithMetadata(new Microsoft.AspNetCore.Antiforgery.RequireAntiforgeryTokenAttribute(true));
app.MapRazorComponents<App>() app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(); .AddInteractiveServerRenderMode()
.RequireAuthorization();
return await app.RunJasperFxCommands(args); return await app.RunJasperFxCommands(args);
static void AddUserClaims(ClaimsIdentity? identity, IEnumerable<string> groups, string? classroom)
{
if (identity is null)
{
return;
}
foreach (var group in groups.Where(group => !string.IsNullOrWhiteSpace(group)))
{
if (!identity.HasClaim(ClaimTypes.Role, group))
{
identity.AddClaim(new Claim(ClaimTypes.Role, group));
}
}
if (!string.IsNullOrWhiteSpace(classroom) && !identity.HasClaim("classroom", classroom))
{
identity.AddClaim(new Claim("classroom", classroom));
}
}
+2 -2
View File
@@ -31,10 +31,10 @@
}, },
"OIDC": { "OIDC": {
"Authority": "https://id.bs18.de/realms/master", "Authority": "https://id.bs18.de/realms/master",
"ClientId": "WollmilchsauDev", "ClientId": "wollmilchsaudev",
"ClientSecret": "WQlhc6lzngs0nkC1TQeRbw16qffHaeg4", "ClientSecret": "WQlhc6lzngs0nkC1TQeRbw16qffHaeg4",
"ResponseType": "code", "ResponseType": "code",
"Scopes": [ "openid", "profile" ] "Scopes": [ "openid", "profile", "gruppen", "KlassenAttribut" ]
}, },
"MSGraph": { "MSGraph": {
"ClientId": "c938782f-2779-45e6-8430-21238e69aa9e", "ClientId": "c938782f-2779-45e6-8430-21238e69aa9e",