我一直在实现自己的JWT令牌Authentication/Authorisation
,而不使用Identity等。
基于这些链接,我成功创建了一个JWT令牌 - 并使用属性[Authorize]
Token Authentication 2 - [我的代码与此完全相同]
我遇到的问题是,在我正在处理的应用程序中,授权基于FEATURE
而不是ROLE
。
这是DB Schema
1. User
-------------------
UserId (PK)
2. Role
-------------------
RoleId (PK)
3. RoleFeatures
-------------------
(RoleId PK, FK)
(FeatureId PK, FK)
4. Features
-------------------
FeatureId (PK)
角色不是预先定义的,但功能是预先定义的,例如创建用户,更新用户
假设我们有2个角色"User Manager"
和"User and Customer Admin"
- 这两个角色的用户都可以Create, Update and Delete
用户。
现在在Application Controller中而不是
[Authorise(Roles="User Manager, User and Customer Admin")]
public IActionResult CreateUser()
我需要这个:
[Authorise(Features="Create User")]
public IActionResult CreateUser()
如何在MVC Core Web API中实现此类JWT令牌授权?
这样做的一种方法是将JWT令牌中的功能保存为声明 - 但问题是角色可以说20个功能,并将它们保存在令牌中会显着增加令牌大小 -
所以我需要的是授权属性的自定义实现,它获取来自JWT令牌的userId(userId是JWT令牌中的Claim),然后从基于UserId的DB获取角色特征并应用授权。
基于.NET核心文档 - 我发现我可以创建一个策略
https://docs.asp.net/en/latest/security/authorization/policies.html
所以我继续创建了需求和需求处理程序,如下所示:
public class FeatureRequirement : IAuthorizationRequirement
{
public string FeatureName { get; set; }
public FeatureRequirement(string featureName) { FeatureName = featureName; }
}
public class FeatureRequirementHandler : AuthorizationHandler<FeatureRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FeatureRequirement requirement)
{
var userId = context.User.Claims.FirstOrDefault(s => s.Type == "UserId");
if (userId == null) { return Task.FromResult(0); }
//TODO: Get User Features from DB based on UserId
var userFeatures = new List<string> { "Create User", "Update User" };
if (userFeatures.Contains(requirement.FeatureName))
{
context.Succeed(requirement);
}
return Task.FromResult(0);
}
}
并在Startup.cs中
services.AddAuthorization(options =>
{
// Create the Policies
// Problem here have to define a policy for each feature
options.AddPolicy("Create User", policy => policy.Requirements.Add(new FeatureRequirement("Create User")));
options.AddPolicy("Update User", policy => policy.Requirements.Add(new FeatureRequirement("Update User")));
});
services.AddScoped<IAuthorizationHandler, FeatureRequirementHandler>();
然后在Controller中:
[Authorise(Policy="Create User")]
public IActionResult CreateUser()
// AND
[Authorise(Policy="Update User")]
public IActionResult UpdateUser()
哪个工作符合预期(如果未将功能分配给用户,则返回403)
问题在于我必须为每个功能创建一个新策略 - 有更好的方法吗?