声称更好的方式而不是角色

时间:2018-04-05 22:16:01

标签: authorization asp.net-core-2.0 roles claims

我正在建立一个网站(前端反应,后端asp.net web api核心2)并试图找出如何进行身份验证/授权。

对于身份验证我几乎都会使用JWTBearer令牌,如果用户名和密码与我在数据库中为用户获得的内容匹配,则给他们一个令牌。

这是我不确定的授权,上次我必须做某事时,你的数据库中有更多角色,然后在他们试图访问某些内容时检查该用户是否具有该角色。

现在我正在看this blog,作者谈到了

  

您可以将有关用户的信息存储为声明,而不是尝试存储用户可能拥有的所有“角色”(例如,管理员,用户,超级用户)。

我对此感到困惑,这是如何工作的。假设我需要一个用户才能看到我网站的秘密区域(即管理区域),但另一个登录的用户无法看到它,因为他是普通用户。

用于提出此声明的信息是什么?什么存储在数据库中?

对于角色,您可以拥有类似用户可以拥有角色(即管理员)的内容,然后在他们尝试执行某些操作时进行检查。

我也想知道前端如何知道要隐藏什么(即表示"管理区域"的链接),你可以发回一个结果说他们有一个允许他们看到的声明管理区域?

2 个答案:

答案 0 :(得分:1)

声明可用于管理比Role更广泛的用例,尤其是在与Policies and Requirements配对时。想到两个例子:

  1. 要求用户具有特定声誉才能编辑记录
  2. 要求用户至少订购21个特定产品
  3. 可以创造一个" Over21"角色,以及" Over1000Reputation"角色,但保持角色成员资格变得笨拙;您需要设置作业,以便在年龄或声誉发生变化时添加(或删除)这些角色的用户。

    相反,请让您的JWT包含Reputation和BirthDate声明:

    identity.AddClaim(new Claim("Reputation", 722));
    identity.AddClaim(new Claim("BirthDate", new DateTime(2000, 1, 1)));
    

    然后,您的代码可以实施RequirementAuthorizationHandler,根据这些声明值计算用户是否应获得授权:

    public class ReputationRequirement : IAuthorizationRequirement
    {
        public int Reputation { get; private set; }
    
        public ReputationRequirement (int reputation)
        {
            Reputation = reputation;
        }
    }
    

    与这些行中的AuthorizationHandler配对:

    public class ReputationHandler : AuthorizationHandler<ReputationRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ReputationRequirement requirement)
        {
            if (!context.User.HasClaim(c => c.Type == "Reputation"))
            {
                return Task.CompletedTask;
            }
    
            var reputation = context.User.FindFirst(c => c.Type == "Reputation").Value as int;
            if (reputation >= requirement.Reputation)  
                context.Succeed(requirement);
            return Task.CompletedTask;
        }
    }
    

    在您的初创公司ConfigurationServices中,您可以为您的要求的特定实例提供名称(Policy):

    services.AddAuthorization(options =>
    {
        options.AddPolicy("Reputation750", policy => policy.Requirements.Add(new ReputationRequirement(750)));
        options.AddPolicy("OldAndWise", policy => 
        {
            policy.Requirements.Add(new ReputationRequirement(750));
            policy.Requirements.Add(new MinimumAgeRequirement(40));
        }
    });
    

    最后,您可以使用策略标记MVC控制器或方法:

    [Authorize(Policy = "OldAndWise")]
    public class StackOverflowWineController : Controller
    {
        // omitted for brevity
    }
    

    请注意,链接的示例包含此简短代码段的详细信息。

    关于数据库中声明的存储,具体取决于用例。将角色视为声明时,您仍然会有something likeUserRolesRoleMembership表。对于ReptuationBirthDate,将它们存储在User表中可能更有意义,而不是某种专用的通用Claims表。

答案 1 :(得分:0)

角色仍然可以像旧版本一样使用。声明只是一种存储更多用户数据并通过身份验证提供更多灵活性的方法。您可以将它们添加到这样的列表中:

List<Claim> claims = new List<Claim> {
    new Claim(ClaimTypes.Name, "username"),
    new Claim(ClaimTypes.Role, "First Role"),
    new Claim(ClaimTypes.Role, "Second Role"),
    new Claim(ClaimTypes.Role, "Third Role")
};

您可以使用[Authorize(Roles = "user, superUser")]授权任何控制器或操作。如果要根据角色向用户显示内容,可以使用@if (User.IsInRole("User"))

从JWT创建开始,您可以查看此课程:https://github.com/neville-nazerane/netcore-jwt-sample/blob/master/website/TokenGenerator.cs

它具有实用程序功能,可以创建具有给定用户名的JWT,也可以使用用户名和逗号分隔的角色字符串。