Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Authorization MVC 3 and Ninject IoC

I have a custom authorization class that inherits from FilterAttribute and implements IAuthorizationFilter. I am using the latest version of Ninject w/ asp.net MVC 3 support.

The problem I have is I am using constructor injection to inject a repository. But by the the time OnAuthorization is called, the repository is null. Here is the code...

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

        }
    }

Filter Binding:

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


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

Update: One thing I noticed is this filter is at controller level. I have other filters at action scope that seem to work properly...could that be the reason?

Update 2: I've confirmed that if I change the filter scope to action, then the repository is available OnAuthorization (not null).

This works below, however I need at controller scope, not action.

this.BindFilter<MyAuthorizeAttribute >(System.Web.Mvc.FilterScope.Action, null).WhenActionMethodHas<MyAuthorizeAttribute >();
like image 515
B Z Avatar asked Apr 06 '11 19:04

B Z


2 Answers

Attributes do not support constructor injection as they are created by the .NET Framework and are not under control of Ninject. If you really want to use a FilterAttribute (which I do not recommend) you'll have to use property injection.

Instead continue what you just began. You need a filter implementing IAuthorizationFilter (not derived from FilterAttribute, just remove it from your code above) and additionally an ordinary attribute to mark the controllers/actions.

Then change the binding:

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

See: https://github.com/ninject/ninject.web.mvc/wiki/MVC3

The problem with you current implementation is that it is found once as filter attribute and once added as normal filter. One for these instances will have the repo injected an the the repo is null for the other one.

NOTE: you can derive from an existing FilterAttribute if this simplifies your implementation. But do not use it as a attribute in this case but use it as an ordinary filter.

like image 128
Remo Gloor Avatar answered Oct 21 '22 17:10

Remo Gloor


It is better to extend the AuthorizeAttribute class so that authorization works correctly with cached requests. You will also need to use Ninject.Web.Mvc

You will need to use Ninject property injection to use your repository. Constructor injection will not work with Attributes.

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

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return base.AuthorizeCore(httpContext);
    }
}
like image 6
Rohan West Avatar answered Oct 21 '22 17:10

Rohan West