我们的应用程序具有PermissionAttribute
的概念。此属性在我们的应用程序的基础层中定义,我们的命令和查询使用该属性进行修饰。由于此属性是在基础层中定义的,因此我们不能(也不希望)让它从FilterAttribute
继承或在其上实现System.Web.Mvc.IActionFilter
。
我们仍然希望将此属性应用于控制器操作,如下所示:
[Permission(Permissions.Administration.ManageUsers)]
public ActionResult Index()
{
return this.View();
}
基于此属性,应该应用适当的安全检查。我一直在浏览MVC代码库以找到适当的钩子来定制MVC行为,以允许基于此自定义属性添加这些安全检查。我虽然创建了一个自定义ControllerActionInvoker
,它从ReflectedControllerDescriptor
方法返回了一个自定义GetControllerDescriptor
,该方法将返回FilterAttribute
,该PermissionAttribute
将根据{{1}的存在而创建但感觉就像很多工作一样,而且我不确定这是走路的正确道路。
定制MVC管道的有效和愉快的方法是什么,以便我们可以处理这个非MVC相关的属性?
答案 0 :(得分:2)
我会这样做。首先像这样创建自己的AuthorizeAttribtues
实现:
public class PermissionAuthoriseAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Leaving the implementation of this to you, but you check if your
//PermissionAttribute is assigned and call it's methods.
if(...)
return true;
//You may want to check this first, depending on your requirements
return base.AuthorizeCore(httpContext);
}
}
然后将此行添加到FilterConfig.cs
文件中,将其应用于整个项目:
filters.Add(new PermissionAuthoriseAttribute());
答案 1 :(得分:2)
我最终做了以下事情:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new PermissionAuthorizationFilter(
() => Global.Container.GetInstance<IUserPermissionChecker>()), 0);
filters.Add(new HandleErrorAttribute());
}
}
public sealed class PermissionAuthorizationFilter : IAuthorizationFilter
{
private readonly Func<IUserPermissionChecker> userPermissionCheckerFactory;
public PermissionAuthorizationFilter(
Func<IUserPermissionChecker> userPermissionCheckerFactory) {
this.userPermissionCheckerFactory = userPermissionCheckerFactory;
}
public void OnAuthorization(AuthorizationContext filterContext) {
var attribute = filterContext.ActionDescriptor
.GetCustomAttributes(typeof(PermissionAttribute), true)
.OfType<PermissionAttribute>()
.SingleOrDefault();
if (attribute != null) {
VerifyPermission(filterContext, attribute.PermissionId);
}
}
private static void VerifyPermission(AuthorizationContext filterContext,
Guid permissionId) {
var permissionChecker = userPermissionCheckerFactory.Invoke();
if (!permissionChecker.HasPermission(permissionId))
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}