基于声明的授权以及在何处添加用户可以执行的操作

Claims-based authorization and where to add what the user can do

我刚刚使用基于声明的授权实现了一个网络 api。用户可以登录系统,并根据用户可以执行的操作从数据库中提取一组声明并添加到 httpContext.User.Identity。

在 Startup.cs 中注册策略后,使用如下内容:

services.AddAuthorization(options =>
{
    options.AddPolicy(PoliciesDefinitions.RequiresVehicleList, policy => policy.RequireClaim(Permissions.VehiclesList.ToString()));

    ...               
});

我可以在我想要授权的控制器方法上使用 Authorize 属性,例如:

Authorize(Policy=PoliciesDefinitions.RequiresDriversList)]
[HttpGet]
public ActionResult Get() { ... }

这工作正常,但今天我更彻底地阅读了微软文档,我在基于声明的授权文档中看到了这个声明:

A claim is a name value pair that represents what the subject is, not what the subject can do

此时我正在做 microsfot 建议不要做的事情。我将用户可以执行的操作(权限)添加到 identity 中。所以,这让我思考,我做错了吗?如果答案是肯定的,您将在哪里存储用户权限以及授权如何工作?

这允许 KVP 和多个值。

// with Razor, you did not specific if it was core 2, 3.1 or Razor

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("Vendors", policy =>
                          policy.RequireClaim("Type.Tykt.org", "Dealer", "Driver", "WholeSaler", "Asset", "Repair"));
    });
}

选项 2:

还有一个claims合集,可以在用户登录成功后添加。

var user = new User {
  Email = "xyz@tykt.org",
  Name =  "xyz"
}

user.Claims.Add(new IdentityUserClaim<string> 
{ 
    ClaimType="your-type",   // your key
    ClaimValue="your-value"  // your value
});

await userManager.CreateAsync(user);

更新Ref MSDN:

这实际上是您对如何存储检索的选择,如果我理解这个问题,您的具体问题是索赔的价值。

通常,映射和验证以类似 PermissionHandler : IAuthorizationHandler 或通用方法 MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement> 的方式进行。其中,加载值,并处理特定权限的需求验证,例如最小年龄,但实际声明(你在说什么/min age policy vs 值通常在数据库中,如 DOB=1/1/1990)与 Principal对象。现在,您可以选择从何处检索声明的价值

在下面的函数中,他从上下文中获取键的值,然后验证

public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   MinimumAgeRequirement requirement)
    {
        if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth &&
                                        c.Issuer == "http://contoso.com"))
        {
            return Task.CompletedTask;
        }

        var dateOfBirth = Convert.ToDateTime(
            // He gets the value on the server-side from any store or 3rd party relayer
            context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth && 
                                        c.Issuer == "http://contoso.com").Value);

        int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
        if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
        {
            calculatedAge--;
        }

        if (calculatedAge >= requirement.MinimumAge)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}