using System.Security.Claims; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Server; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; namespace Aaru.Server.New.Components.Account; // This is a server-side AuthenticationStateProvider that revalidates the security stamp for the connected user // every 30 minutes an interactive circuit is connected. sealed class IdentityRevalidatingAuthenticationStateProvider (ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory, IOptions options) : RevalidatingServerAuthenticationStateProvider(loggerFactory) { protected override TimeSpan RevalidationInterval => TimeSpan.FromMinutes(30); protected override async Task ValidateAuthenticationStateAsync( AuthenticationState authenticationState, CancellationToken cancellationToken) { // Get the user manager from a new scope to ensure it fetches fresh data await using AsyncServiceScope scope = scopeFactory.CreateAsyncScope(); UserManager userManager = scope.ServiceProvider.GetRequiredService>(); return await ValidateSecurityStampAsync(userManager, authenticationState.User); } async Task ValidateSecurityStampAsync(UserManager userManager, ClaimsPrincipal principal) { IdentityUser? user = await userManager.GetUserAsync(principal); if(user is null) return false; if(!userManager.SupportsUserSecurityStamp) return true; string? principalStamp = principal.FindFirstValue(options.Value.ClaimsIdentity.SecurityStampClaimType); string userStamp = await userManager.GetSecurityStampAsync(user); return principalStamp == userStamp; } }