如何授权用户在 blazor wasm 客户端的角色?
How to authorize user's role in client side of blazor wasm?
环境
- Asp.Net核心5.0
- Blazor WebAssembly 应用程序(Asp.Net 核心托管)
- Asp.Net 核心身份(使用 Identity Server 4)
问题
我想在服务器端和客户端之间使用基于角色的授权。
我可以正确登录并且 UserManager.IsInRoleAsync(user, "admin")
returns 在服务器端是正确的。
但是 @attribute [Authorize(Roles = "admin")]
和 <AuthorizeView Roles="admin">
在客户端都不起作用。在客户端也 User.Identity.IsInRole("admin")
returns False。
如何在客户端获取用户的角色?
代码
Server.csproj
// Startup.ConfigureServices()
services.AddDefaultIdentity<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 2;
options.Password.RequireNonAlphanumeric = false;
options.User.RequireUniqueEmail = true;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
// Startup.Configure()
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
// RolesController.Get()
var userid = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
var currentUser = await userManager.FindByIdAsync(userid);
return await userManager.IsInRoleAsync(currentUser, "admin"); // Returns True
Client.csproj
// Program.Main()
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("WebAppIdentity.ServerAPI"));
builder.Services.AddApiAuthorization();
// Test.razor
<AuthorizeView Roles="admin">
<Authorizing>
Authorizing...
</Authorizing>
<NotAuthorized>
You are not an admin. // Always here
</NotAuthorized>
<Authorized>
Hello, admin!
</Authorized>
</AuthorizeView>
<button @onclick="ShowInfo">Show Info</button>
<p>@infoString</p>
@code
{
[CascadingParameter]
private Task<AuthenticationState> stateTask { get; set; }
private string infoString { get; set; }
private async void ShowInfo()
{
var user = (await stateTask).User;
infoString = $"Is admin: {user.IsInRole("admin")}"; // Always False
}
}
目前有 two accepted ways 个处理此问题。
第一个
#1 通过调用 AddRoles
配置身份以使用角色
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
#2 配置身份服务器以将角色声明放入 id 令牌和访问令牌中,并防止 JwtSecurityTokenHandler 中角色的默认映射。
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
// Need to do this as it maps "role" to ClaimTypes.Role and causes issues
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
#3 在您的 blazor 应用程序上使用 [Authorize(Roles = "admin")] 或您的应用程序定义的任何其他角色。
#4 在您受保护的资源 API 上使用 [Authorize(Roles = "admin")] 或您的应用程序定义的任何其他角色。
第二个
#1 添加 Class 以在客户端上配置 options.UserOptions.RoleClaim
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.Options;
namespace App.Client.Services
{
public class ApiAuthorizationOptionsConfiguration
: IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>
{
public void Configure(RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
options.UserOptions.RoleClaim ??= "role";
}
public void PostConfigure(string name, RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
if (string.Equals(name, Options.DefaultName))
{
Configure(options);
}
}
}
}
#2 修改Program.cs文件调用ApiAuthorizationOptionsConfiguration并配置角色声明。
using App.Client.Services;
...
namespace App.Client
{
public class Program
{
public static async Task Main(string[] args)
{
...
builder.Services.AddAuthorizationCore();
builder.Services.AddApiAuthorization();
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton<
IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>,
ApiAuthorizationOptionsConfiguration>());
...
}
}
}
环境
- Asp.Net核心5.0
- Blazor WebAssembly 应用程序(Asp.Net 核心托管)
- Asp.Net 核心身份(使用 Identity Server 4)
问题
我想在服务器端和客户端之间使用基于角色的授权。
我可以正确登录并且 UserManager.IsInRoleAsync(user, "admin")
returns 在服务器端是正确的。
但是 @attribute [Authorize(Roles = "admin")]
和 <AuthorizeView Roles="admin">
在客户端都不起作用。在客户端也 User.Identity.IsInRole("admin")
returns False。
如何在客户端获取用户的角色?
代码
Server.csproj
// Startup.ConfigureServices()
services.AddDefaultIdentity<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 2;
options.Password.RequireNonAlphanumeric = false;
options.User.RequireUniqueEmail = true;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
// Startup.Configure()
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
// RolesController.Get()
var userid = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
var currentUser = await userManager.FindByIdAsync(userid);
return await userManager.IsInRoleAsync(currentUser, "admin"); // Returns True
Client.csproj
// Program.Main()
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("WebAppIdentity.ServerAPI"));
builder.Services.AddApiAuthorization();
// Test.razor
<AuthorizeView Roles="admin">
<Authorizing>
Authorizing...
</Authorizing>
<NotAuthorized>
You are not an admin. // Always here
</NotAuthorized>
<Authorized>
Hello, admin!
</Authorized>
</AuthorizeView>
<button @onclick="ShowInfo">Show Info</button>
<p>@infoString</p>
@code
{
[CascadingParameter]
private Task<AuthenticationState> stateTask { get; set; }
private string infoString { get; set; }
private async void ShowInfo()
{
var user = (await stateTask).User;
infoString = $"Is admin: {user.IsInRole("admin")}"; // Always False
}
}
目前有 two accepted ways 个处理此问题。
第一个
#1 通过调用 AddRoles
配置身份以使用角色services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
#2 配置身份服务器以将角色声明放入 id 令牌和访问令牌中,并防止 JwtSecurityTokenHandler 中角色的默认映射。
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
// Need to do this as it maps "role" to ClaimTypes.Role and causes issues
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
#3 在您的 blazor 应用程序上使用 [Authorize(Roles = "admin")] 或您的应用程序定义的任何其他角色。
#4 在您受保护的资源 API 上使用 [Authorize(Roles = "admin")] 或您的应用程序定义的任何其他角色。
第二个
#1 添加 Class 以在客户端上配置 options.UserOptions.RoleClaim
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.Options;
namespace App.Client.Services
{
public class ApiAuthorizationOptionsConfiguration
: IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>
{
public void Configure(RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
options.UserOptions.RoleClaim ??= "role";
}
public void PostConfigure(string name, RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
if (string.Equals(name, Options.DefaultName))
{
Configure(options);
}
}
}
}
#2 修改Program.cs文件调用ApiAuthorizationOptionsConfiguration并配置角色声明。
using App.Client.Services;
...
namespace App.Client
{
public class Program
{
public static async Task Main(string[] args)
{
...
builder.Services.AddAuthorizationCore();
builder.Services.AddApiAuthorization();
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton<
IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>,
ApiAuthorizationOptionsConfiguration>());
...
}
}
}