自定义授权MVC 3和Ninject IoC

时间:2011-04-06 19:59:44

标签: asp.net-mvc asp.net-mvc-3 ninject

我有一个自定义授权类,它继承自FilterAttribute并实现IAuthorizationFilter。我正在使用最新版本的Ninject w / asp.net MVC 3支持。

我遇到的问题是我使用构造函数注入来注入存储库。但是在调用OnAuthorization时,存储库为null。这是代码......

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: 我已经确认,如果我将过滤器范围更改为action,那么存储库可用OnAuthorization(非null)。

这可以在下面工作,但我需要在控制器范围,而不是行动。

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

3 个答案:

答案 0 :(得分:10)

属性不支持构造函数注入,因为它们是由.NET Framework创建的,并且不受Ninject的控制。如果你真的想使用FilterAttribute(我不推荐),你将不得不使用属性注入。

相反,继续你刚刚开始的。您需要一个实现IAuthorizationFilter的过滤器(不是从FilterAttribute派生,只是从上面的代码中删除它),另外还需要一个标记控制器/操作的普通属性。

然后更改绑定:

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

请参阅:https://github.com/ninject/ninject.web.mvc/wiki/MVC3

您当前实现的问题是,它被发现一次作为过滤器属性,并且一次添加为普通过滤器。对于这些实例,一个将注入repo,另一个repo为null。

注意:如果这样可以简化您的实现,则可以从现有的FilterAttribute派生。但是在这种情况下不要将它用作属性,而是将其用作普通过滤器。

答案 1 :(得分:6)

最好扩展AuthorizeAttribute类,以便授权可以正常使用缓存的请求。您还需要使用Ninject.Web.Mvc

您需要使用Ninject属性注入来使用您的存储库。构造函数注入不适用于Attributes。

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

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return base.AuthorizeCore(httpContext);
    }
}

答案 2 :(得分:0)

以为我会在这里添加我的解决方案似乎工作正常。

创建了一个扩展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负责存储库注入。希望这有助于某人。