using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Server; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.Security.Claims; using System.Threading.Tasks; using System.Threading; using System; using Oqtane.Infrastructure; using Oqtane.Extensions; namespace Oqtane.Providers { internal 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) { await using var scope = scopeFactory.CreateAsyncScope(); var tenantManager = scope.ServiceProvider.GetRequiredService(); tenantManager.SetTenant(authenticationState.User.TenantId()); var userManager = scope.ServiceProvider.GetRequiredService>(); return await ValidateSecurityStampAsync(userManager, authenticationState.User); } private async Task ValidateSecurityStampAsync(UserManager userManager, ClaimsPrincipal principal) { var user = await userManager.FindByNameAsync(principal.Identity.Name); if (user is null) { return false; } else if (!userManager.SupportsUserSecurityStamp) { return true; } else { var principalStamp = principal.FindFirstValue(options.Value.ClaimsIdentity.SecurityStampClaimType); var userStamp = await userManager.GetSecurityStampAsync(user); //return principalStamp == userStamp; // security stamps need to be persisted in principal - they are stored in AspNetUsers return true; } } } }