ASP.NET MVC允许用户在设计时为功能(即操作(分配权限。
[Authorize(Roles = "Administrator,ContentEditor")]
public ActionResult Foo()
{
return View();
}
要真正检查权限,可以在(Razor(视图中使用以下语句:
@if (User.IsInRole("ContentEditor"))
{
<div>This will be visible only to users in the ContentEditor role.</div>
}
这种方法的问题是,所有权限都必须在设计时设置并分配为属性。(属性是用DLL编译的,所以我目前知道没有任何机制可以在运行时应用属性(以允许额外权限(,如[Authorize(Roles="Administrator,ContentEditor"(]。
在我们的用例中,客户端需要能够在部署后更改哪些用户拥有哪些权限。
例如,客户端可能希望允许ContentEditor
角色中的用户编辑特定类型的一些内容。也许用户不被允许编辑查找表值,但现在客户端希望允许这样做,而不授予用户在下一个更高角色中的所有权限。相反,客户端只想修改用户当前角色的可用权限。
有哪些策略可用于允许在属性之外定义MVC控制器/视图/操作的权限(如在数据库中(,并在运行时进行评估和应用
如果可能的话,我们非常希望尽可能地坚持ASP.NET成员资格和角色提供程序功能,以便我们能够继续利用它提供的其他好处。
提前感谢您的任何想法或见解。
有哪些策略可用于允许MVC上的权限要在属性之外定义的控制器/视图/操作(如数据库(,并在运行时进行评估和应用?
自定义Authorize属性是实现这一点的一种可能性:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
Roles = ... go ahead and fetch those roles dynamically from wherever they are stored
return base.AuthorizeCore(httpContext);
}
}
然后:
[MyAuthorize]
public ActionResult Foo()
{
return View();
}
因为我很懒,所以我不介意滚动自己的属性,并为此使用了FluentSecurity。除了能够在运行时应用规则之外,它还允许使用自定义方式检查角色成员身份。在我的案例中,我为每个角色都设置了一个配置文件,然后我实现了以下内容;
// Map application roles to configuration settings
private static readonly Dictionary<ApplicationRole, string>
RoleToConfigurationMapper = new Dictionary<ApplicationRole, string>
{
{ ApplicationRole.ExceptionLogViewer, "ExceptionLogViewerGroups" }
};
然后像一样应用应用程序角色
SecurityConfigurator.Configure(
configuration =>
{
configuration.GetAuthenticationStatusFrom(() =>
HttpContext.Current.User.Identity.IsAuthenticated);
configuration.GetRolesFrom(() =>
GetApplicationRolesForPrincipal(HttpContext.Current.User));
configuration.ForAllControllers().DenyAnonymousAccess();
configuration.For<Areas.Administration.Controllers.LogViewerController>()
.RequireRole(ApplicationRole.ExceptionLogViewer);
});
filters.Add(new HandleSecurityAttribute());
然后通过进行检查
public static object[] GetApplicationRolesForPrincipal(IPrincipal principal)
{
if (principal == null)
{
return new object[0];
}
List<object> roles = new List<object>();
foreach (KeyValuePair<ApplicationRole, string> configurationMap in
RoleToConfigurationMapper)
{
string mappedRoles = (string)Properties.Settings.Default[configurationMap.Value];
if (string.IsNullOrEmpty(mappedRoles))
{
continue;
}
string[] individualRoles = mappedRoles.Split(',');
foreach (string indvidualRole in individualRoles)
{
if (!roles.Contains(configurationMap.Key) && principal.IsInRole(indvidualRole))
{
roles.Add(configurationMap.Key);
if (!roles.Contains(ApplicationRole.AnyAdministrationFunction))
{
roles.Add(ApplicationRole.AnyAdministrationFunction);
}
}
}
}
return roles.ToArray();
}
当然,您可以从数据库中提取角色。这件事的好处是,我可以在开发过程中应用不同的规则,而且有人已经为我做了艰苦的工作!
您还可以考虑执行基于任务/活动的安全性,并将执行这些任务的权限动态分配给不同的组
http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/
您可能需要对提供商进行一点破坏才能处理此问题,但可以与.net授权保持一致
http://www.lhotka.net/weblog/PermissionbasedAuthorizationVsRolebasedAuthorization.aspx
如果您需要进行基于方法或控制器的授权(拒绝访问整个方法或控制器(,那么您可以覆盖控制器库中的OnAuthorization并进行自己的授权。然后,您可以构建一个表来查找分配给该控制器/方法的权限,然后从那里开始。
你也可以做一个自定义的全局过滤器,这是非常相似的。
使用第二种方法的另一种选择是这样说:
@if (User.IsInRole(Model.MethodRoles))
{
<div>This will be visible only to users in the ContentEditor role.</div>
}
然后在控制器中用分配给该方法的角色填充MethodRoles。