AuthorizeView 策略:Blazor 页面不显示
AuthorizeView Policy: Blazor Page not displaying
IdentityServer returns AuthenticationScheme:Bearer 被禁止。
我检查了 AccessToken,它包含范围 "account.read" 但是 blazor 不显示该页面
我是不是漏掉了什么?
Startup.cs
services.AddAuthorization(options =>
{
options.AddPolicy("Account", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account"));
options.AddPolicy("AccountWrite", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.write"));
options.AddPolicy("AccountRead", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.read"));
});
Blazor 页面
<AuthorizeView> <p> you are logged in </p> <AuthorizeView>
<AuthorizeView Policy="AccountRead">
<p> you have account.read access </p>
</AuthorizeView>
这是框架中的全局问题,尚未修复。
此问题是由于目前不支持 Blazor 读取作为数组发送的声明。
例如用户:["c","r","u","d"]
无法读取。
要纠正此问题,您需要添加 ClaimsPrincipalFactory。
例如
public class ArrayClaimsPrincipalFactory<TAccount> : AccountClaimsPrincipalFactory<TAccount> where TAccount : RemoteUserAccount
{
public ArrayClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{ }
// when a user belongs to multiple roles, IS4 returns a single claim with a serialised array of values
// this class improves the original factory by deserializing the claims in the correct way
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(TAccount account, RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
var claimsIdentity = (ClaimsIdentity)user.Identity;
if (account != null)
{
foreach (var kvp in account.AdditionalProperties)
{
var name = kvp.Key;
var value = kvp.Value;
if (value != null &&
(value is JsonElement element && element.ValueKind == JsonValueKind.Array))
{
claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(kvp.Key));
var claims = element.EnumerateArray()
.Select(x => new Claim(kvp.Key, x.ToString()));
claimsIdentity.AddClaims(claims);
}
}
}
return user;
}
}
然后在您的 program/startup 中注册(取决于您是否使用 .core 托管),如下所示:
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("oidc", options.ProviderOptions);
})
.AddAccountClaimsPrincipalFactory<ArrayClaimsPrincipalFactory<RemoteUserAccount>>();
IdentityServer returns AuthenticationScheme:Bearer 被禁止。
我检查了 AccessToken,它包含范围 "account.read" 但是 blazor 不显示该页面
我是不是漏掉了什么?
Startup.cs
services.AddAuthorization(options =>
{
options.AddPolicy("Account", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account"));
options.AddPolicy("AccountWrite", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.write"));
options.AddPolicy("AccountRead", policy => policy.RequireClaim(JwtClaimTypes.Scope, "account", "account.read"));
});
Blazor 页面
<AuthorizeView> <p> you are logged in </p> <AuthorizeView>
<AuthorizeView Policy="AccountRead">
<p> you have account.read access </p>
</AuthorizeView>
这是框架中的全局问题,尚未修复。
此问题是由于目前不支持 Blazor 读取作为数组发送的声明。
例如用户:["c","r","u","d"]
无法读取。
要纠正此问题,您需要添加 ClaimsPrincipalFactory。
例如
public class ArrayClaimsPrincipalFactory<TAccount> : AccountClaimsPrincipalFactory<TAccount> where TAccount : RemoteUserAccount
{
public ArrayClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{ }
// when a user belongs to multiple roles, IS4 returns a single claim with a serialised array of values
// this class improves the original factory by deserializing the claims in the correct way
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(TAccount account, RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
var claimsIdentity = (ClaimsIdentity)user.Identity;
if (account != null)
{
foreach (var kvp in account.AdditionalProperties)
{
var name = kvp.Key;
var value = kvp.Value;
if (value != null &&
(value is JsonElement element && element.ValueKind == JsonValueKind.Array))
{
claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(kvp.Key));
var claims = element.EnumerateArray()
.Select(x => new Claim(kvp.Key, x.ToString()));
claimsIdentity.AddClaims(claims);
}
}
}
return user;
}
}
然后在您的 program/startup 中注册(取决于您是否使用 .core 托管),如下所示:
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("oidc", options.ProviderOptions);
})
.AddAccountClaimsPrincipalFactory<ArrayClaimsPrincipalFactory<RemoteUserAccount>>();