2014-09-17 2 views
3

Наше приложение имеет понятие PermissionAttribute. Этот атрибут определяется в базовом слое нашего приложения, и наши команды и запросы украшены этим атрибутом. Поскольку этот атрибут определен в базовом слое, мы не можем (и не хотим) позволить ему наследовать от FilterAttribute или реализовать на нем System.Web.Mvc.IActionFilter.Применение атрибутов, не связанных с MVC, для действий MVC

Тем не менее, мы хотели бы применить этот атрибут к контроллеру действия следующим образом:

[Permission(Permissions.Administration.ManageUsers)] 
public ActionResult Index() 
{ 
    return this.View(); 
} 

На основе этого атрибута надлежащие проверки безопасности должны быть применены. Я просматриваю базу кода MVC, чтобы найти подходящие крючки для настройки поведения MVC, чтобы добавить эти проверки безопасности на основе этого настраиваемого атрибута. Я хотел бы создать пользовательский ControllerActionInvoker, который возвратил пользовательский ReflectedControllerDescriptor из своего метода GetControllerDescriptor, который вернет FilterAttribute, который будет создан на основе существования PermissionAttribute, но он чувствует себя как большая работа, и я не уверен, что это правильный путь для ходьбы.

Что было бы эффективным и приятным способом настройки конвейера MVC, чтобы мы могли справиться с этим атрибутом, не связанным с MVC?

+0

Не могли бы вы унаследовать от 'AuthoriseAttribute', поставить логику там, чтобы проверить свой' PermissionAttribtue' и добавить его в ваше приложение по всему миру? – DavidG

+0

Просто создайте глобальный фильтр в проекте mvc и проверьте атрибут Permission на выполненном действии. :) – dariol

+0

@DavidG, но в этом случае мне нужно применить два атрибута к действию или не я? Это уродливо и подвержено ошибкам. – Steven

ответ

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

Да, это отличное решение. Я закончил реализацию 'IAuthorizationFilter' напрямую, но ваш ответ достаточно близок. – Steven

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(); 
     } 
    } 
} 
+2

Ницца. Раздражающе, нет простого способа обойти место службы (но, как говорится в статье в вашем блоге, не делайте DI в атрибутах!) – DavidG

+0

@Steven: Вы можете ввести завод для IUserPermissionChecker в constuctor PermissionAuthorizatinonFilter вместо разрешения через DependencyResolver. –

+0

@ Ric.Net: Да, это намного чище. Обновлен мой ответ. – Steven