using System.Net.Http.Json; using System.Security.Claims; using ChessCubing.App.Models.Auth; using Microsoft.AspNetCore.Components.Authorization; namespace ChessCubing.App.Services; public sealed class AppAuthenticationStateProvider(HttpClient httpClient) : AuthenticationStateProvider { private static readonly AuthenticationState AnonymousState = new(new ClaimsPrincipal(new ClaimsIdentity())); private AuthenticationState? _cachedState; public override async Task GetAuthenticationStateAsync() { if (_cachedState is not null) { return _cachedState; } _cachedState = await LoadStateAsync(); return _cachedState; } public async Task RefreshAsync() { _cachedState = await LoadStateAsync(); NotifyAuthenticationStateChanged(Task.FromResult(_cachedState)); } public void SetAuthenticated(AuthSessionResponse session) { _cachedState = new AuthenticationState(BuildPrincipal(session)); NotifyAuthenticationStateChanged(Task.FromResult(_cachedState)); } public void SetAnonymous() { _cachedState = AnonymousState; NotifyAuthenticationStateChanged(Task.FromResult(_cachedState)); } private async Task LoadStateAsync() { try { var session = await httpClient.GetFromJsonAsync("api/auth/session"); if (session is null || !session.IsAuthenticated) { return AnonymousState; } return new AuthenticationState(BuildPrincipal(session)); } catch { return AnonymousState; } } private static ClaimsPrincipal BuildPrincipal(AuthSessionResponse session) { if (!session.IsAuthenticated) { return AnonymousState.User; } var claims = new List(); if (!string.IsNullOrWhiteSpace(session.Subject)) { claims.Add(new Claim("sub", session.Subject)); claims.Add(new Claim(ClaimTypes.NameIdentifier, session.Subject)); } if (!string.IsNullOrWhiteSpace(session.Username)) { claims.Add(new Claim("preferred_username", session.Username)); claims.Add(new Claim(ClaimTypes.Name, session.Username)); } if (!string.IsNullOrWhiteSpace(session.Name)) { claims.Add(new Claim("name", session.Name)); } if (!string.IsNullOrWhiteSpace(session.Email)) { claims.Add(new Claim("email", session.Email)); claims.Add(new Claim(ClaimTypes.Email, session.Email)); } foreach (var role in session.Roles.Where(role => !string.IsNullOrWhiteSpace(role))) { claims.Add(new Claim("role", role)); claims.Add(new Claim(ClaimTypes.Role, role)); } return new ClaimsPrincipal(new ClaimsIdentity(claims, "ChessCubingCookie")); } }