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 ran on the server, isAdmin
is true when my logged-in user is 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>