将与MVC无关的属性应用于MVC操作
本文关键字:MVC 应用于 操作 属性 将与 | 更新日期: 2023-09-27 18:22:20
我们的应用程序具有PermissionAttribute
的概念。这个属性是在我们的应用程序的底层中定义的,我们的命令和查询都是用这个属性装饰的。由于这个属性是在底层中定义的,我们不能(也不想)让它继承FilterAttribute
或在它上面实现System.Web.Mvc.IActionFilter
尽管如此,我们还是希望将此属性应用于控制器操作,如下所示:
[Permission(Permissions.Administration.ManageUsers)]
public ActionResult Index()
{
return this.View();
}
基于此属性,应该应用适当的安全检查。我一直在浏览MVC代码库,以找到合适的挂钩来自定义MVC行为,从而允许基于此自定义属性添加这些安全检查。我想创建一个自定义ControllerActionInvoker
,它从GetControllerDescriptor
方法返回一个自定义的ReflectedControllerDescriptor
,该方法将返回基于PermissionAttribute
的存在而创建的FilterAttribute
,但这感觉工作量很大,我不确定这是正确的路径。
什么是定制MVC管道的有效且愉快的方式,以便我们能够处理这个与MVC无关的属性?
我会这样做。首先创建自己的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());
我最终做了以下事情:
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();
}
}
}