Пользовательская авторизация MVC 3 и Ninject IoC - PullRequest
10 голосов
/ 06 апреля 2011

У меня есть пользовательский класс авторизации, который наследуется от FilterAttribute и реализует IAuthorizationFilter.Я использую последнюю версию Ninject с поддержкой MVC 3.

Проблема, с которой я столкнулся, заключается в том, что я использую конструктор для инъекции в хранилище.Но к тому времени, когда вызывается OnAuthorization, хранилище становится пустым.Вот код ...

public class MyAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
    {
        private readonly IMyRepo _MyRepo;

        public MyAuthorizeAttribute() { }
        public MyAuthorizeAttribute(IMyRepo myRepo)
        {
            _MyRepo= myRepo; //this gets initialized
        }


        public void OnAuthorization(AuthorizationContext filterContext)
        {
            _MyRepo.DoStuff(); //<< Null, wtf

        }
    }

Привязка фильтра:

Bind<IMyRepo>().To<MyRepo>().InRequestScope();


this.BindFilter<MyAuthorizeAttribute >(System.Web.Mvc.FilterScope.Controller, null).WhenControllerHas<MyAuthorizeAttribute >();

Обновление: Одна вещь, которую я заметил, - это фильтр на уровне контроллера.У меня есть другие фильтры в области действия, которые, кажется, работают должным образом ... может ли это быть причиной?

Обновление 2: Я подтвердил, что если я изменю область действия фильтра на действие,тогда хранилище доступно OnAuthorization (не ноль).

Это работает ниже, однако мне нужно в области действия контроллера, а не действия.

this.BindFilter<MyAuthorizeAttribute >(System.Web.Mvc.FilterScope.Action, null).WhenActionMethodHas<MyAuthorizeAttribute >();

Ответы [ 3 ]

10 голосов
/ 07 апреля 2011

Атрибуты не поддерживают внедрение конструктора, так как они создаются .NET Framework и не контролируются Ninject.Если вы действительно хотите использовать FilterAttribute (который я не рекомендую), вам придется использовать инъекцию свойств.

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

Затем измените привязку:

this.BindFilter<MyAuthorizeFilter>(FilterScope.Controller, 0).WhenControllerHas<MyAuthorizeAttribute>();

См .: https://github.com/ninject/ninject.web.mvc/wiki/MVC3

Проблема с текущей реализацией заключается в том, что она однажды найдена в качестве атрибута фильтра и однажды добавлена ​​в качестве обычного фильтра.В одном случае для этих репозиториев будет введено хранилище, а в другом хранилище пустое.

ПРИМЕЧАНИЕ. Вы можете извлечь из существующего атрибута FilterAttribute, если это упрощает вашу реализацию.Но не используйте его в качестве атрибута в этом случае, а используйте его как обычный фильтр.

6 голосов
/ 07 апреля 2011

Лучше расширить класс AuthorizeAttribute, чтобы авторизация правильно работала с кэшированными запросами.Вам также нужно будет использовать Ninject.Web.Mvc

. Для использования вашего репозитория вам необходимо использовать инъекцию свойств Ninject.Внедрение в конструктор не будет работать с атрибутами.

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    [Inject]
    public IMyRepo MyRepo { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return base.AuthorizeCore(httpContext);
    }
}
0 голосов
/ 17 января 2014

Просто подумал, что я добавлю свое решение здесь, как кажется, работает нормально.

Создан класс, который расширяет AuthorizeAttribute и принимает интерфейс репозитория в конструкторе.

Этот класс затем переопределяет функцию AuthorizeCore:

public class MyRoleAttribute : AuthorizeAttribute
{
    private ICRepository repository;

    public MyRoleAttribute(ICRepository Repo)
    {
        repository = Repo;
    }

protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        //Check if user authenticated
        if (!httpContext.Request.IsAuthenticated)
            return false;

         //Can access items in the query string if needed
         var id = (httpContext.Request.RequestContext.RouteData.Values["id"] as string)
         ??(httpContext.Request["id"] as string);

          //Can access repository that has been injected
          if (repository.IsGroupCreator(.....))
            {

                return true;

            }
            else
            {

                return false;

            }
    }
}

Затем для внедрения в репозиторий я добавил следующий код в файл mvc NinjectWebCommon.cs:

kernel.BindFilter<MyRoleAttribute>(FilterScope.Action, 0).When(
(controllerContext, actionDescriptor) => actionDescriptor.ActionName == "MyAction");

Это позволяет мне контролировать, какие действия мне нужны для атрибута, а ninject позаботится о внедрении репозитория. Надеюсь, это кому-нибудь поможет.

...