无法将 Okta 组声明映射到 Blazor WASM 客户端中的角色声明
Unable to map Okta Groups Claim to Roles Claim in Blazor WASM Client
问题
我正在尝试根据用户角色利用 Blazor 中的 AuthorizeView
组件 hide/show 页面的不同部分。我正在使用连接到 OKTA 的 OIDC 作为身份验证提供程序。
默认情况下,OKTA return 角色 范围作为 [=][=] 中的 Groups 声明34=]。我试图强制身份验证提供程序查看组对角色的声明,如下面的代码所示。
我的测试帐户具有适当的权限,正如我在 Groups 声明中看到的那样。我无法使此映射正常工作。
有没有人遇到过类似的问题and/or找到了解决方案?
示例代码
-- Program.cs --
public static async Task Main(string[] args)
{
...
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = "***";
options.ProviderOptions.ClientId = "***";
options.ProviderOptions.DefaultScopes.Add("roles");
options.ProviderOptions.ResponseType = "token id_token";
options.UserOptions.RoleClaim = "groups";
options.UserOptions.NameClaim = "name";
});
....
}
-- MyPage.razor --
<AuthorizeView Roles="Admin">
<Authorized>
Authorized
</Authorized>
<NotAuthorized>
Not Authorized
</NotAuthorized>
</AuthorizeView>
解决方案
我找到了以下文章:http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4376/Implementing-Roles-In-Blazor-WebAssembly.aspx,其中解释了如何使用自定义 Claims Principal Factory。
我从文章中复制了代码并根据需要进行了相应调整
RolesClaimsPrincipalFactory.cs
public class RolesClaimsPrincipalFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public RolesClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor) : base(accessor)
{
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account, RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (!user.Identity.IsAuthenticated)
{
return user;
}
var identity = (ClaimsIdentity) user.Identity;
var roleClaims = identity.FindAll(claim => claim.Type == "groups");
if (roleClaims == null || !roleClaims.Any())
{
return user;
}
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties["groups"];
if (!(rolesElem is JsonElement roles))
{
return user;
}
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
return user;
}
}
Program.cs
public class Program
{
public static async Task Main(string[] args)
{
...
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = ******;
options.ProviderOptions.ClientId = ******;
options.ProviderOptions.DefaultScopes.Add("roles");
options.ProviderOptions.ResponseType = "token id_token";
options.UserOptions.RoleClaim = "role";
}).AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();
...
}
}
要点
- 您需要指定 RoleClaim
options.UserOptions.RoleClaim = "role";
。如果不这样做,您将得到 NullReferenceException。
- 通过使用扩展方法
AddAccountClaimsPrincipalFactory<T>()
来实现自定义声明主体。
- 这个解决方案似乎是 OKTA Auth、Blazor WASM 和 OIDC 的小众案例。
问题
我正在尝试根据用户角色利用 Blazor 中的 AuthorizeView
组件 hide/show 页面的不同部分。我正在使用连接到 OKTA 的 OIDC 作为身份验证提供程序。
默认情况下,OKTA return 角色 范围作为 [=][=] 中的 Groups 声明34=]。我试图强制身份验证提供程序查看组对角色的声明,如下面的代码所示。
我的测试帐户具有适当的权限,正如我在 Groups 声明中看到的那样。我无法使此映射正常工作。
有没有人遇到过类似的问题and/or找到了解决方案?
示例代码
-- Program.cs --
public static async Task Main(string[] args)
{
...
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = "***";
options.ProviderOptions.ClientId = "***";
options.ProviderOptions.DefaultScopes.Add("roles");
options.ProviderOptions.ResponseType = "token id_token";
options.UserOptions.RoleClaim = "groups";
options.UserOptions.NameClaim = "name";
});
....
}
-- MyPage.razor --
<AuthorizeView Roles="Admin">
<Authorized>
Authorized
</Authorized>
<NotAuthorized>
Not Authorized
</NotAuthorized>
</AuthorizeView>
解决方案
我找到了以下文章:http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4376/Implementing-Roles-In-Blazor-WebAssembly.aspx,其中解释了如何使用自定义 Claims Principal Factory。
我从文章中复制了代码并根据需要进行了相应调整
RolesClaimsPrincipalFactory.cs
public class RolesClaimsPrincipalFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public RolesClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor) : base(accessor)
{
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account, RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (!user.Identity.IsAuthenticated)
{
return user;
}
var identity = (ClaimsIdentity) user.Identity;
var roleClaims = identity.FindAll(claim => claim.Type == "groups");
if (roleClaims == null || !roleClaims.Any())
{
return user;
}
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties["groups"];
if (!(rolesElem is JsonElement roles))
{
return user;
}
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
return user;
}
}
Program.cs
public class Program
{
public static async Task Main(string[] args)
{
...
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = ******;
options.ProviderOptions.ClientId = ******;
options.ProviderOptions.DefaultScopes.Add("roles");
options.ProviderOptions.ResponseType = "token id_token";
options.UserOptions.RoleClaim = "role";
}).AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();
...
}
}
要点
- 您需要指定 RoleClaim
options.UserOptions.RoleClaim = "role";
。如果不这样做,您将得到 NullReferenceException。 - 通过使用扩展方法
AddAccountClaimsPrincipalFactory<T>()
来实现自定义声明主体。 - 这个解决方案似乎是 OKTA Auth、Blazor WASM 和 OIDC 的小众案例。