gpt4 book ai didi

c# - Clarifying Identity Authorization : using Claims as Roles, Roles and Claims or 角色声明

转载 作者:太空狗 更新时间:2023-10-29 17:59:58 29 4
gpt4 key购买 nike

我从 ASP.NET Identity 的声明授权开始,如果我的应用程序中需要“角色”概念,我想阐明处理它们的方式。

注意:我对这个真的很陌生,所以所有的概念都在我脑海中飞舞,请多多关照,对于任何概念的进一步澄清/更正将不胜感激。

1.- 假设,我需要 Admin 和 User 角色的“角色”概念,所以我的第一个想法是向 ApplicationUser 添加声明,例如:

user.Claims.Add(new IdentityUserClaim<string> { ClaimType = "Role", ClaimValue = "Admin" });

*“用户”是 ApplicationUser

但后来我读到它已经由框架完成,因为它有一些预定义的声明类型,所以上面的代码可以是:

user.Claims.Add(new IdentityUserClaim<string> { ClaimType = ClaimTypes.Role, ClaimValue = "Admin" });

这种方法正确吗?或者我应该使用“旧”角色概念并向用户添加角色,例如:

await _roleManager.CreateAsync(new IdentityRole("Admin"));    
await _userManager.AddToRoleAsync(user, "Admin");

2.- 现在假设我将角色定义为声明,我如何检查它们的授权?我的意思是,它会起作用吗?

[Authorize(Roles = "Admin")]

或者我应该包含一个政策声明来检查角色声明吗?

/* In startup ConfigureServices method*/
options.AddPolicy("IsAdmin", policy => {
policy.RequireClaim(ClaimTypes.Role, "Admin");
});

...

/*In a controller class*/
[Authorize(Policy = "IsAdmin")]
<controller here>

3.- 现在,存储自定义声明的正确方法是什么?我的意思是,ASP.NET 的 ClaimTypes 类只是一堆 const string 值,所有关于 Claims 的示例代码都将它们存储在类似的类中,例如:

public static class ClaimData
{
public static List<string> AdminClaims { get; set; } = new List<string>
{
"Add User",
"Edit User",
"Delete User"
};
}

可以吗?

最后说明。- 我还在互联网上看到了“角色声明”的概念,这篇博文对此进行了解释:http://benfoster.io/blog/asp-net-identity-role-claims

那是什么?如果我还不够困惑,现在还有第三种授权用户的方式。使用角色作为声明是否更好?

最佳答案

您描述的方法似乎是正确的。一切都取决于您的要求。

假设您的应用程序中有多个功能,如果您选择使用角色,则属于该功能的代码必须每次检查用户是否在一组特定的角色中才能使用该功能。当功能和角色增长时,这种方法变得非常难以管理,因为您必须考虑将角色组合到每个功能中。在此示例中,只有 PowerUserAdministrator 用户才能执行管理操作 X。现在,这看起来简单明了,但是,如果您添加一个新角色 ALittleBitMorePowerful 会发生什么,这是一个 User 也可以执行 X操作。要获得此结果,您必须检查所有内容并更改检查(这意味着重新测试整个内容)。

如果您设计的功能X 带有声明CanPerformX,您将引入一个抽象层:您的代码将不关心用户的角色,但会检查只为自己的主张。如果您曾经修改声明与用户的关联方式,您的有效代码将不会改变(这最终意味着没有引入正式的回归)。

角色被设计为广泛的,而声明被设计为细粒度的。但是,当您在链接中阅读时,您可能会认为一个角色是“大角色”,或者一个角色是“小角色”。

我发布了一小段我的代码,它支持自定义角色但固定声明。定义声明

    internal static class PolicyClaims
{
public const string AdministratorClaim = @"http://myorganization/2019/administrator";
public const string Operation1Claim = @"http://myorganization/2019/op1";
public const string Operation2Claim = @"http://myorganization/2019/op2";
public const string ObtainedClaim = @"true";
}

定义策略

    internal static class Policies
{
public const string RequireAdministrator = "RequireAdministrator";
public const string RequireOp1 = "RequireOp1";
public const string RequireOp2 = "RequireOp2";

public const string AlwaysDeny = "AlwaysDeny";

public static void ConfigurePolicies(IServiceCollection services)
{
services.AddAuthorization(options => options.AddPolicy(RequireAdministrator, policy => policy.RequireClaim(PolicyClaims.AdministratorClaim)));
services.AddAuthorization(options => options.AddPolicy(RequireOp1, policy => policy.RequireClaim(PolicyClaims.Operation1Claim)));
services.AddAuthorization(options => options.AddPolicy(RequireOp2, policy => policy.RequireClaim(PolicyClaims.Operation2Claim)));
services.AddAuthorization(options => options.AddPolicy(AlwaysDeny, policy => policy.RequireUserName("THIS$USER\n\r\t\0cannot be created")));
}
}

Startup.RegisterServices 中注册策略

    Policies.ConfigurePolicies(services);

在对用户进行身份验证的地方,根据您的逻辑决定需要添加哪些声明(省略了一些部分以关注概念)

    [AllowAnonymous]
[Route("api/authentication/authenticate")]
[HttpPost()]
public async Task<IActionResult> Authenticate([FromBody] LoginModel model)
{
if (ModelState.IsValid)
{
var user = m_UserManager.Users.FirstOrDefault(x => x.UserName == model.UserName);

if (user == null)
{
...
}
else
{
var result = await m_SignInManager.CheckPasswordSignInAsync(user, model.Password, false);
if (result.Succeeded)
{
var handler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.Name, model.UserName)
}),
Expires = DateTime.UtcNow.AddHours(2),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(InstanceSettings.JWTKey), SecurityAlgorithms.HmacSha256Signature)
};

var roles = await m_UserManager.GetRolesAsync(user);

AddClaims(tokenDescriptor, roles);

var token = handler.CreateToken(tokenDescriptor);
var tokenString = handler.WriteToken(token);

return ...
}
else
{
...
}
}
}
return ...
}

private static void AddClaims(SecurityTokenDescriptor tokenDescriptor, IList<string> roles)
{
if (roles.Any(x => string.Equals(Constants.AdministratorRoleName, x, StringComparison.OrdinalIgnoreCase)))
{
tokenDescriptor.Subject.AddClaim(new Claim(PolicyClaims.AdministratorClaim, PolicyClaims.ObtainedClaim));

tokenDescriptor.Subject.AddClaim(new Claim(PolicyClaims.Operation1Claim, PolicyClaims.ObtainedClaim));
tokenDescriptor.Subject.AddClaim(new Claim(PolicyClaims.Operation2Claim, PolicyClaims.ObtainedClaim));
}
... query the database and add each claim with value PolicyClaims.ObtainedClaim ...
}

最后,您可以使用策略来保护您的代码:

    [Authorize(Policy = Policies.RequireAdministrator)]
[HttpPost("execute")]
public async Task<IActionResult> ExecuteOperation([FromBody] CommandModel model)
{
...
}

请注意,在这种方法中,我将某些声明硬编码给管理员,因为我想阻止管理员删除某些声明。但是,这不是强制性的。

关于c# - Clarifying Identity Authorization : using Claims as Roles, Roles and Claims or 角色声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45997100/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com