I have a component using auto render mode:
@attribute [RenderModeInteractiveAuto]
I inject the AuthenticationStateProvider
:
@inject Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider _auth
Now, in my code, if I do something like this:
var state = await _auth.GetAuthenticationStateAsync();
var user = state.User;
var isAdmin = user.IsInRole("admin");
When this is run on the server, isAdmin
is true for logged-in users in the admin
role. However, on WASM, this is false. Plus, on the server side, the name claim correctly contains the user name whereas in WASM it contains the e-mail address.
Is this still a bug, or do I have to tweak some settings to get the correct identity propagated?
Authentication in Blazor 8 WASM is performed by PersistingServerAuthenticationStateProvider
on the server persisting the Identity using the UserInfo
class to the wasm client via its PersistentAuthenticationStateProvider
I achieved this and forced everyone to be an "Administrator" for demonstration/testing purposes as follows:
Updated UserInfo to include Roles
public class UserInfo
{
public required string UserId { get; set; }
public required string Email { get; set; }
public required UserRole[]? Roles { get; set; }
}
public class UserRole
{
public required string Name { get; set; }
}
On the server project update PersistingServerAuthenticationStateProvider.cs
Just below these two lines
var userId = principal.FindFirst(_options.ClaimsIdentity.UserIdClaimType)?.Value;
var email = principal.FindFirst(_options.ClaimsIdentity.EmailClaimType)?.Value;
I added this to persist the role claims
UserRole[] userRoles =
principal.FindAll(_options.ClaimsIdentity.RoleClaimType)
.Select(a=> new UserRole { Name = a.Value })
.Append(new UserRole { Name = "Administrator" }) // <== remove this
.ToArray();
Then in the client to create the ClaimsIdentity update PersistentAuthenticationStateProvider.cs
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
if (!persistentState.TryTakeFromJson<UserInfo>(nameof(UserInfo), out var userInfo) || userInfo is null)
{
return _unauthenticatedTask;
}
List<Claim> claims = [
new Claim(ClaimTypes.NameIdentifier, userInfo.UserId),
new Claim(ClaimTypes.Name, userInfo.Email), // <== Name Claim Issue
new Claim(ClaimTypes.Email, userInfo.Email)];
foreach (var role in userInfo?.Roles ?? [])
{
claims.Add(new Claim(ClaimTypes.Role, role.Name));
}
return Task.FromResult(
new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims.ToArray(),
authenticationType: nameof(PersistentAuthenticationStateProvider)))));
}
@page "/auth"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@attribute [RenderModeInteractiveWebAssembly]
<PageTitle>Auth</PageTitle>
<h1>You are authenticated</h1>
<AuthorizeView>
Hello @context.User.Identity?.Name!
</AuthorizeView>
<AuthorizeView Roles="Administrator">
[Administrator]
</AuthorizeView>