Атрибут Ninject Binding для фильтрации с аргументами конструктора - PullRequest
16 голосов
/ 29 ноября 2011

Я прочитал столько ответов, сколько мог для этого, но они, кажется, не соответствуют одной детали.

Проблема в том, что, связывая фильтр действий (с сервисом, внедренным контроллером) с соответствующим атрибутом, я не смог выяснить, как передать значения параметра / свойства из атрибута в его связанный фильтр. Ниже приведен код, а под ним мой предполагаемый поддельный код:

Фильтр и атрибут

public class AuthorizationFilter : IAuthorizationFilter
{
    private readonly IAuthorizationService _authorizationService;
    private readonly UserRoles _requiredRoles;   // Enum

    public AuthorizationFilter(IAuthorizationService authorizationService, UserRoles requiredRoles)
    {
        _authorizationService = authorizationService;
        _requiredRoles = requiredRoles;
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Session == null)
            HandleUnauthorizedRequest(filterContext);
        else {
            var authorized = _authorizationService.IsUserInRole((UserSessionInfoViewModel) filterContext.HttpContext.Session["user"], _requiredRoles);
            if (!authorized)
                HandleUnauthorizedRequest(filterContext);
            // else TODO: deal with cache... 
        }
    }
}

public class RequireRolesAttribute : FilterAttribute
{
    public readonly UserRoles RequiredRoles;

    public RequireRolesAttribute(UserRoles requiredRoles)
    {
        RequiredRoles = requiredRoles;
    }        
}

Привязки фильтров / атрибутов

kernel.BindFilter<AuthorizationFilter>(FilterScope.Controller, 0)
      .WhenControllerHas<RequireRolesAttribute>();
kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0)
      .WhenActionMethodHas<RequireRolesAttribute>();

Это должно убедиться, что любой контроллер / действие, украшенное [RolesRequired], привязано к фильтру. Все идет нормально. Теперь я хочу объявить через атрибут роли (так же, как стандартный AuthorizeAttribute) и передать эти значения в фильтр, который фактически выполняет авторизацию.

Намеренный / поддельный код:

[RequireRoles(UserRoles.Author)]
public ActionResult Index()
{
    // blah
}

В частности,

Что требуется для информирования AuthorizationFilter о ролях? Может ли фильтр / объект доступ к аргументам, переданным конструктору атрибута? Может ли фильтр / объект извлекать их из открытого свойства атрибутов?

Для справки, эти статьи очень помогли, но не отвечайте на этот вопрос:

Внедрение зависимостей с атрибутом Ninject и Filter для asp.net mvc

Пользовательская авторизация MVC 3 и Ninject IoC

B Z, Remo Gloor, другие ... как я могу это сделать?

Ответы [ 2 ]

20 голосов
/ 30 ноября 2011

Я понял это (благодаря указаниям и документации Remo).

Используйте соответствующее расширение .WithConstructorArgument независимо от того, привязываетесь ли вы к контроллеру или фильтру действий. Например, привязка моего фильтра действий выглядит следующим образом:

kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0)
      .WhenActionMethodHas<RequireRolesAttribute>()
      .WithConstructorArgumentFromActionAttribute<RequireRolesAttribute>("requiredRoles", o => o.RequiredRoles);

Как только я понял подпись Func <> , все стало ясно. Лучший способ найти способ справиться с этим - это

  1. сделать тип расширения специфичным для моего атрибута

    .WithConstructorArgumentFromActionAttribute<TAttribute>()
    
  2. получить значение из объекта обратного вызова (вашего атрибута) через лямбду:

    ("argumentName", o => o.PropertyName)
    
9 голосов
/ 16 июля 2012

и для внедрения метода расширения BindFilter не забудьте добавить;

using Ninject.Web.Mvc.FilterBindingSyntax;
...