Closed travaille-dev closed 5 months ago
Hey @halter73 let me know if there's any more information that I can provide to help out.
If you change roleType: null
to roleType: RoleClaimType
in your ToClaimsPrincipal()
method, [Authorize(Roles = "Admin")]
should be respected as long as the user is only in one role.
However, Entra ID can return multiple roles
claims, so UserInfo.Roles
should probably be updated from a string
to a string[]
. If you do that, FromClaimsPrincipal()
should be updated so Roles = GetRequiredClaim(principal, RoleClaimType),
becomes something like Roles = principal.FindAll(RoleClaimType).Select(c => c.Value),
. And ToClaimsPrincipal()
should be updated to .Concat(Roles.Select(role => new Claim(RoleClaimType, role)))
instead of always including a single roles Claim
.
Does this give you enough information to resolve your issue?
I've tested out the case of multiple roles and still receive the same invalid error when setting the [Authorize(Roles="Admin")
attribute.
Here's my UserInfo
using System.Security.Claims;
namespace RNR.Client;
// Add properties to this class and update the server and client AuthenticationStateProviders
// to expose more information about the authenticated user to the client.
public sealed class UserInfo
{
public required string Email { get; init; }
public required string Name { get; init; }
public required string[] Roles { get; init; }
public required string UserId { get; init; }
private const string UserIdClaimType = "preferred_username";
public const string NameClaimType = "name";
private const string RoleClaimType = "roles";
private const string CustomClaimType = "userid";
public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
new()
{
Email = GetRequiredClaim(principal, UserIdClaimType),
Name = GetRequiredClaim(principal, NameClaimType),
Roles = principal.FindAll(RoleClaimType).Select(c => c.Value).ToArray(),
UserId = (GetRequiredClaim(principal, UserIdClaimType).Split("@")[0])
};
public ClaimsPrincipal ToClaimsPrincipal()
{
return new ClaimsPrincipal(new ClaimsIdentity(
Roles.Select(role => new Claim(RoleClaimType, role))
.Concat(new[]
{
new Claim(UserIdClaimType, Email),
new Claim(NameClaimType, Name),
new Claim(CustomClaimType, UserId)
}),
authenticationType: nameof(UserInfo),
nameType: NameClaimType,
roleType: RoleClaimType));
}
private static string GetRequiredClaim(ClaimsPrincipal principal, string claimType) =>
principal.FindFirst(claimType)?.Value ??
throw new InvalidOperationException($"Could not find required '{claimType}' claim.");
}
I believe I found something interesting. I added the following to my user-claims page
@attribute [Authorize]
<PageTitle>User Claims</PageTitle>
<AuthorizeView Roles="Test">
<Authorized>
Neat
</Authorized>
<NotAuthorized>
Not Neat
</NotAuthorized>
</AuthorizeView>
So when I load the page, initially it loads as "Not Neat" and then refreshes into neat.
I am using global clientside interactivity, but it looks like the initial render of the page isn't actually using the FromClaimsPrincipal
function before evaluating.
Well I think I got it now. Just had to update the oidc options in my base project Program.cs
file to use the RoleClaimType as roles
instead of role
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
Glad that you've figured this out, @travaille-dev. Closing, as no further action is pending for us on this one.
Is there an existing issue for this?
Describe the bug
I'm working through the Blazor 8 OIDC web app example and I've ran into a snag where I'm trying to select what roles have access to specific pages.
I'm able to access and view my claims (including roles) with the basic
[Authorize]
attribute, but when I specify[Authorize(Roles="Admin")]
I receive an access denied redirection.I've updated the UserInfo Class to the following to get the role claim added into what's stored clientside.
And I've modified the UserClaims PageComponent to the following
Expected Behavior
I expect to be able to be able to see the user-claims page when I specify my role in the
[Authorize(Roles="")]
AttributeSteps To Reproduce
For this I'm using an Entra App Registration + Enterprise application in order to set up an Admin role and assign my userid to the Admin role.
Those are the prerequisites for getting started, but other than that filling out your clientid/secret/authority should be the same.
I've referenced above the only deviations from the templated code.
Exceptions (if any)
No response
.NET Version
8.0.201
Anything else?