using Microsoft.AspNetCore.Components; 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; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; namespace GWMS.UI.Areas.Identity { public class RevalidatingIdentityAuthenticationStateProvider : RevalidatingServerAuthenticationStateProvider where TUser : class { #region Private Fields private readonly IdentityOptions _options; private readonly IServiceScopeFactory _scopeFactory; #endregion Private Fields #region Public Constructors public RevalidatingIdentityAuthenticationStateProvider( ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory, IOptions optionsAccessor) : base(loggerFactory) { _scopeFactory = scopeFactory; _options = optionsAccessor.Value; } #endregion Public Constructors #region Protected Properties protected override TimeSpan RevalidationInterval => TimeSpan.FromMinutes(30); #endregion Protected Properties #region Private Methods private async Task ValidateSecurityStampAsync(UserManager userManager, ClaimsPrincipal principal) { var user = await userManager.GetUserAsync(principal); if (user == null) { return false; } else if (!userManager.SupportsUserSecurityStamp) { return true; } else { var principalStamp = principal.FindFirstValue(_options.ClaimsIdentity.SecurityStampClaimType); var userStamp = await userManager.GetSecurityStampAsync(user); return principalStamp == userStamp; } } #endregion Private Methods #region Protected Methods protected override async Task ValidateAuthenticationStateAsync( AuthenticationState authenticationState, CancellationToken cancellationToken) { // Get the user manager from a new scope to ensure it fetches fresh data var scope = _scopeFactory.CreateScope(); try { var userManager = scope.ServiceProvider.GetRequiredService>(); return await ValidateSecurityStampAsync(userManager, authenticationState.User); } finally { if (scope is IAsyncDisposable asyncDisposable) { await asyncDisposable.DisposeAsync(); } else { scope.Dispose(); } } } #endregion Protected Methods } }