通用位置授权规则MVC .NET中的最佳实践

时间:2014-07-03 20:36:46

标签: asp.net-mvc controller authorization

我目前面临的情况是,我正在使用特定的授权属性来装饰我的HttpPost Controller操作方法,以及在我的HttpGet中指定相同的规则以确保我的视图中没有某些功能。

是否有最佳实践或更好的解决方案,以便我可以在一个地方指定实际业务规则以启用DRY以及不会陷入代码爆炸的情况,即为每个规则具有特定的Authorize属性。

我目前的情况如下:

public class MyController
{

   [HttpGet]
   public ActionResult List()
   {
       // This action is responsible for showing the list of records.  Each record
       // can potentially have a delete link but this is only shown for Administrators

       var viewModel = new MyViewModel()
       {
          CanDeleteRecordRole = Role.Administrator, // Duplicated rule here
          // other properties
       }
   }

   [HttpPost]
   [Authorize(Role.Administrator)]
   public ActionResult Delete(int id)
   {
      /// do stuff
   }
}

public class Role
{
   public const string Administrator = "Administrator";
}

然后在我看来使用扩展方法我会使用CanDeleteRecordRole,例如:

@if(Model.DisplayIfAuthorized(Model.CanDeleteRecordRole))
{
   <th>Delete record</th>
}

// and for td columns

@if(Model.DisplayIfAuthorized(Model.CanDeleteRecordRole))
{
   <td>My action link here for deletion</td>
}

2 个答案:

答案 0 :(得分:1)

是的,肯定有一种方法可以将业务逻辑与授权逻辑分离并进行干预。该区域称为外部化授权管理(EAM)(参见Gartner's definition)。

要实现EAM,您需要使用的不仅仅是角色。您需要使用属性,其中属性基本上只是一个键值对,例如citizenship=Canadianclearance=SECRETdepartment=sales ...

角色还不够。引用之前在评论中分享的article

  

基于角色的授权检查有什么不对?

     

使用基于角色的检查创建了大量授权系统,那么它们有什么问题?很多东西,包括文档和耦合,建模和封装问题,以及需求的增长和变化。

基于角色的授权(也称为基于角色的访问控制或RBAC)不够灵活,无法表达丰富的授权方案。您需要转向ABAC,即NIST定义的Attribute-Based Access Control模型。

使用ABAC,您可以轻松实施以下规则:

  • 用户可以编辑他/她拥有的文件
  • 用户可以查看属于同一部门的所有文档
  • 如果文档是草稿且文档敏感度等于或小于用户许可,则具有角色审阅者的用户可以批准文档。

您在ABAC中可以表达的内容没有限制。

实现ABAC的事实上的标准和技术是XACML,eXtensible Access Control Markup Language。 XACML定义:

  • 具有概念的授权体系结构
    • 达成决策的外部政策决策点(PDP)
    • 保护您的应用程序/代码/ API并呼叫PDP的策略执行点(PEP)
    • 用于检索其他属性和元数据的政策信息点(PIP)。
  • 请求/响应方案:如何提出问题并获得答案,例如 Alice可以查看文档#123吗?
  • 一种丰富的政策语言,用于实施政策,例如我之前提供的示例。

在XACML中,所有策略都集中在一个位置。一些好处包括:   - 更快的开发时间:您不再需要在应用程序中编写授权代码(if / else)   - 更好的安全性:无论语言或技术如何,您都可以在所有应用程序中使用相同的策略。因此,我的答案并非特定于.NET   - 更好的审计功能:如果将authZ逻辑移动到基于策略的中央点,则更容易检查它们   - 实施DRY原则。

这些只是一些好处。

有几种开源和供应商解决方案,例如:

HTH, 大卫。

答案 1 :(得分:1)

我过去解决这个问题的方法是创建一个抽象。不是引用允许执行内容的角色,而是引用包含允许执行内容的角色的字符串常量。像这样:

public class Role
{
    public const string DeleteRoles = "Administrator, role2, role3";
    ....
}

然后创建一个可以解释这些字符串常量的方法(我把它放在自定义原则中):

public class CustomPrincipal
{
    ...
    public bool IsInRoles(string roles)
    {
        bool authorized = false;

        var roles = roles.Split(',');
        foreach (var role in roles)
        {
            if (this.CurrentPrincipal.IsInRole(role)
            {
                authorized = true;
                break;
            }
        }

        return authorized;
    }
    ...
}

然后创建一个自定义Authorization属性,可以通过IsInRoles()方法使用这些字符串常量:

public class CustomAuthorizeAttribute: AuthorizeAttribute
{
    public string Roles { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var isAuthorized = base.AuthorizeCore(httpContext);
        if (!isAuthorized)
        {
            return false;
        }

        isAuthorized = CustomPrincipal.Current.IsInRoles(this.Roles);

        return isAuthorized;
    }

}
你在Action方法中使用的

[HttpPost]
[CustomAuthorize(Roles = Role.DeleteRoles)]
public ActionResult Delete(int id)
{
    /// do stuff
}

然后在视图中,您可以直接使用IsInRoles()方法:

@if(CustomPrincipal.Current.IsInRoles(Role.DeleteRoles))
{
   <th>Delete record</th>
}

您可以通过各种方式实现这一点,但关键是抽象。