托管 ASP.NET-Core-Blazor-WebAssembly-App 中基于角色的授权
Role based authorization in hosted ASP.NET-Core-Blazor-WebAssembly-App
我尝试在我的 Blazor 项目中使用角色。我或多或少以这个 https://code-maze.com/using-roles-in-blazor-webassembly-hosted-applications/ 教程
为自己定位
我在数据库中创建了角色,并且一切正常,例如登录等。我加了
services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDBContext>(opt =>
{
opt.IdentityResources["openid"].UserClaims.Add("role");
opt.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
在 Startup.cs 文件中。为我的用户创建一个“角色”声明,但是当我登录时我没有看到角色声明。
s_hash: nz4meiUsDlXBa8pOfipRmw
sid: 792E67E7F29DF24F13045EECD0DCC6C2
sub: e999a53a-8c76-4737-a202-dabe9e9eeceb
auth_time: 1628245115
idp: local
amr: ["pwd"]
preferred_username: waiter2000@gmx.de
name: waiter2000@gmx.de
问题是我几个小时都无法使用基于角色的授权,因为不知何故我的应用程序没有按应有的方式创建声明字段。
@HenriquePombo 我以为角色会通过登录自动分配。通常我有一个登录名,通过在 Register.cshtml.cs.
中注册分配给一个角色
string UserRole = Request.Form["RoleSelect"];
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email };
var result_CreateAsync = await _userManager.CreateAsync(user, Input.Password);
var result_AddToRolesAsync = await _userManager.AddToRolesAsync(user, new[] { UserRole });
@HenriquePombo
我添加了 class 就像在教程中解释的那样
public class CustomUserFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
var claimsIdentity = (ClaimsIdentity)user.Identity;
if (account != null)
{
MapArrayClaimsToMultipleSeparateClaims(account, claimsIdentity);
}
return user;
}
private void MapArrayClaimsToMultipleSeparateClaims(RemoteUserAccount account, ClaimsIdentity claimsIdentity)
{
foreach (var prop in account.AdditionalProperties)
{
var key = prop.Key;
var value = prop.Value;
if (value != null &&
(value is JsonElement element && element.ValueKind == JsonValueKind.Array))
{
claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(prop.Key));
var claims = element.EnumerateArray()
.Select(x => new Claim(prop.Key, x.ToString()));
claimsIdentity.AddClaims(claims);
}
}
}
}
然后我将服务添加到客户端 Program.cs
builder.Services.AddApiAuthorization().AddAccountClaimsPrincipalFactory<CustomUserFactory>();
请记住我使用的是 Blazor Server,所以有些事情可能会有所不同(尤其是在启动时,我会说)。还有一些具体的事情你可以改变你正在使用的例子(例如我正在使用 SessionStorage 等)
另外,我关注了这个 Blazor 教程播放列表 Blazor Tutorial 以帮助我完成这些事情。最好的问候。
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
//Allow the use of Authentication and Authorization in my program
app.UseAuthentication();
app.UseAuthorization();
}
public void ConfigureServices(IServiceCollection services)
{
...
//Service I added for handling authentication related stuff
services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
}
Class CustomAuthenticationStateProvider
public async Task MarkUserAsAuthenticated(UserModel user)
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.FirstName + " " + user.LastName),
new Claim(ClaimTypes.Email, user.EmailAddress),
new Claim(Claims.UserCredentials, user.UserCredentials),
}, "apiauth_type");
var roles = await GetUserRoles(user.UserCredentials);
foreach(var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.Role, role.Name));
}
var user1 = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user1)));
foreach (var claim in identity.Claims)
{
await _sessionStorageService.SetItemAsStringAsync(claim.Type, claim.Value);
}
}
然后在某个地方:
private readonly AuthenticationStateProvider _customAuthenticationStateProvider;
...
await ((CustomAuthenticationStateProvider)_customAuthenticationStateProvider).MarkUserAsAuthenticated(loginUser);
我自己解决了这个问题。我现在要永远放弃编程,埋葬自己。这是一种耻辱。 Sooo...我在 Register.html.cs 中有“角色”而不是单个“角色”。不同的是:
_userManager.AddToRoleAsync(user, UserRole )
和
await _userManager.AddToRolesAsync(user, new[] { UserRole });
现在,当我创建一个具有这个小差异的新用户时,一切正常。
谢谢@HenriquePombo 非常感谢您的时间和建议。
我尝试在我的 Blazor 项目中使用角色。我或多或少以这个 https://code-maze.com/using-roles-in-blazor-webassembly-hosted-applications/ 教程
为自己定位我在数据库中创建了角色,并且一切正常,例如登录等。我加了
services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDBContext>(opt =>
{
opt.IdentityResources["openid"].UserClaims.Add("role");
opt.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
在 Startup.cs 文件中。为我的用户创建一个“角色”声明,但是当我登录时我没有看到角色声明。
s_hash: nz4meiUsDlXBa8pOfipRmw
sid: 792E67E7F29DF24F13045EECD0DCC6C2
sub: e999a53a-8c76-4737-a202-dabe9e9eeceb
auth_time: 1628245115
idp: local
amr: ["pwd"]
preferred_username: waiter2000@gmx.de
name: waiter2000@gmx.de
问题是我几个小时都无法使用基于角色的授权,因为不知何故我的应用程序没有按应有的方式创建声明字段。
@HenriquePombo 我以为角色会通过登录自动分配。通常我有一个登录名,通过在 Register.cshtml.cs.
中注册分配给一个角色string UserRole = Request.Form["RoleSelect"];
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email };
var result_CreateAsync = await _userManager.CreateAsync(user, Input.Password);
var result_AddToRolesAsync = await _userManager.AddToRolesAsync(user, new[] { UserRole });
@HenriquePombo
我添加了 class 就像在教程中解释的那样
public class CustomUserFactory : AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
var claimsIdentity = (ClaimsIdentity)user.Identity;
if (account != null)
{
MapArrayClaimsToMultipleSeparateClaims(account, claimsIdentity);
}
return user;
}
private void MapArrayClaimsToMultipleSeparateClaims(RemoteUserAccount account, ClaimsIdentity claimsIdentity)
{
foreach (var prop in account.AdditionalProperties)
{
var key = prop.Key;
var value = prop.Value;
if (value != null &&
(value is JsonElement element && element.ValueKind == JsonValueKind.Array))
{
claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(prop.Key));
var claims = element.EnumerateArray()
.Select(x => new Claim(prop.Key, x.ToString()));
claimsIdentity.AddClaims(claims);
}
}
}
}
然后我将服务添加到客户端 Program.cs
builder.Services.AddApiAuthorization().AddAccountClaimsPrincipalFactory<CustomUserFactory>();
请记住我使用的是 Blazor Server,所以有些事情可能会有所不同(尤其是在启动时,我会说)。还有一些具体的事情你可以改变你正在使用的例子(例如我正在使用 SessionStorage 等)
另外,我关注了这个 Blazor 教程播放列表 Blazor Tutorial 以帮助我完成这些事情。最好的问候。
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
//Allow the use of Authentication and Authorization in my program
app.UseAuthentication();
app.UseAuthorization();
}
public void ConfigureServices(IServiceCollection services)
{
...
//Service I added for handling authentication related stuff
services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
}
Class CustomAuthenticationStateProvider
public async Task MarkUserAsAuthenticated(UserModel user)
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.FirstName + " " + user.LastName),
new Claim(ClaimTypes.Email, user.EmailAddress),
new Claim(Claims.UserCredentials, user.UserCredentials),
}, "apiauth_type");
var roles = await GetUserRoles(user.UserCredentials);
foreach(var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.Role, role.Name));
}
var user1 = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user1)));
foreach (var claim in identity.Claims)
{
await _sessionStorageService.SetItemAsStringAsync(claim.Type, claim.Value);
}
}
然后在某个地方:
private readonly AuthenticationStateProvider _customAuthenticationStateProvider;
...
await ((CustomAuthenticationStateProvider)_customAuthenticationStateProvider).MarkUserAsAuthenticated(loginUser);
我自己解决了这个问题。我现在要永远放弃编程,埋葬自己。这是一种耻辱。 Sooo...我在 Register.html.cs 中有“角色”而不是单个“角色”。不同的是:
_userManager.AddToRoleAsync(user, UserRole )
和
await _userManager.AddToRolesAsync(user, new[] { UserRole });
现在,当我创建一个具有这个小差异的新用户时,一切正常。 谢谢@HenriquePombo 非常感谢您的时间和建议。