Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

ASP.NET Core 8 + Blazor - How to update authentication state when using an API endpoint to log in

$
0
0

I'm using the Blazor web app template (server + client + identity + EF Core). The template automatically creates a server-side authentication state provider (PersistingRevalidatingAuthenticationStateProvider) as well as one on the client side (PersistentAuthenticationStateProvider). Authentication works as expected on both the server side and the client side.

Now I'm trying to add an API so the user will call an API endpoint to log in. So in Login.razor, I've replaced SignInManager.PasswordSignInAsync with a post call into the API. The login works, and I can see when I inspect the objects that @context.User.Identity.IsAuthenticated is properly set to true, but when I navigate to a different page, @context.User.Identity?.IsAuthenticated is false on those pages. I figured I have to update the authentication state in PersistingRevalidatingAuthenticationStateProvider but that hasn't worked. What am I missing?

In the code below, I've only added the AuthenticateUser method:

internal sealed class PersistingRevalidatingAuthenticationStateProvider : RevalidatingServerAuthenticationStateProvider{    private readonly IServiceScopeFactory scopeFactory;    private readonly PersistentComponentState state;    private readonly IdentityOptions options;    private readonly PersistingComponentStateSubscription subscription;    private Task<AuthenticationState>? authenticationStateTask;    public PersistingRevalidatingAuthenticationStateProvider(        ILoggerFactory loggerFactory,        IServiceScopeFactory serviceScopeFactory,        PersistentComponentState persistentComponentState,        IOptions<IdentityOptions> optionsAccessor)        : base(loggerFactory)    {        scopeFactory = serviceScopeFactory;        state = persistentComponentState;        options = optionsAccessor.Value;        AuthenticationStateChanged += OnAuthenticationStateChanged;        subscription = state.RegisterOnPersisting(OnPersistingAsync, RenderMode.InteractiveWebAssembly);    }    protected override TimeSpan RevalidationInterval => TimeSpan.FromMinutes(30);    protected override async Task<bool> ValidateAuthenticationStateAsync(        AuthenticationState authenticationState, CancellationToken cancellationToken)    {        // Get the user manager from a new scope to ensure it fetches fresh data        await using var scope = scopeFactory.CreateAsyncScope();        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();        return await ValidateSecurityStampAsync(userManager, authenticationState.User);    }    private async Task<bool> ValidateSecurityStampAsync(UserManager<ApplicationUser> userManager, ClaimsPrincipal principal)    {        var user = await userManager.GetUserAsync(principal);        if (user is 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;        }    }    private void OnAuthenticationStateChanged(Task<AuthenticationState> task)    {        authenticationStateTask = task;    }    private async Task OnPersistingAsync()    {        if (authenticationStateTask is null)        {            throw new UnreachableException($"Authentication state not set in {nameof(OnPersistingAsync)}().");        }        var authenticationState = await authenticationStateTask;        var principal = authenticationState.User;        if (principal.Identity?.IsAuthenticated == true)        {            var userId = principal.FindFirst(options.ClaimsIdentity.UserIdClaimType)?.Value;            var email = principal.FindFirst(options.ClaimsIdentity.EmailClaimType)?.Value;            if (userId != null && email != null)            {                state.PersistAsJson(nameof(UserInfo), new UserInfo                {                    UserId = userId,                    Email = email,                });            }        }    }    public void AuthenticateUser(UserSession userSession)    {        var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(        [            new(ClaimTypes.NameIdentifier, userSession.UserId.ToString()),            new(ClaimTypes.Name, userSession.Email),            new(ClaimTypes.Email, userSession.Email),            new(ClaimTypes.Role, userSession.Role),            new("Permissions", String.Join(",", userSession.Permissions))        ]));        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal)));    }    protected override void Dispose(bool disposing)    {        subscription.Dispose();        AuthenticationStateChanged -= OnAuthenticationStateChanged;        base.Dispose(disposing);    }}

Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>