我目前面临的情况是,我正在使用特定的授权属性来装饰我的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>
}
答案 0 :(得分:1)
是的,肯定有一种方法可以将业务逻辑与授权逻辑分离并进行干预。该区域称为外部化授权管理(EAM)(参见Gartner's definition)。
要实现EAM,您需要使用的不仅仅是角色。您需要使用属性,其中属性基本上只是一个键值对,例如citizenship=Canadian
,clearance=SECRET
,department=sales
...
角色还不够。引用之前在评论中分享的article:
基于角色的授权检查有什么不对?
使用基于角色的检查创建了大量授权系统,那么它们有什么问题?很多东西,包括文档和耦合,建模和封装问题,以及需求的增长和变化。
基于角色的授权(也称为基于角色的访问控制或RBAC)不够灵活,无法表达丰富的授权方案。您需要转向ABAC,即NIST定义的Attribute-Based Access Control模型。
使用ABAC,您可以轻松实施以下规则:
您在ABAC中可以表达的内容没有限制。
实现ABAC的事实上的标准和技术是XACML,eXtensible Access Control Markup Language。 XACML定义:
在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>
}
您可以通过各种方式实现这一点,但关键是抽象。