How do I pass in the repository to an authorize attribute in ASP.NET MVC

蹲街弑〆低调 提交于 2019-12-10 13:46:41

问题


I am castle Windsor and it works great for controller constructors in passing in the repository that is being used.

private IStoryRepository Repository;
public StoryController(IStoryRepository Repository)
{
    this.Repository = Repository;                   
}

Now I have an Action that is in the admin area to display the main admin menu. I have used a custom authorisation attribute which will just check that the logged in user is an admin (just an isAdmin flag in the users table)

 [AdminAuthorize]
 public ActionResult Menu()

 private IStoryRepository Repository;
 /// <summary>
 /// Initializes a new instance of the <see cref="AdminAuthorizeAttribute"/> class.
 /// </summary>
 public AdminAuthorizeAttribute(IStoryRepository Repository)
 {
     this.Repository = Repository;
 }

 /// <summary>
 /// Checks if the user is authorised
 /// </summary>
 /// <param name="httpContext">The HTTP context.</param>
 /// <returns>
 ///    <c>true</c> if authorized; otherwise, <c>false</c>.
 /// </returns>
 protected override bool AuthorizeCore(HttpContextBase httpContext)
 {
    return this.Repository.UserIsAdmin(httpContext.User.Identity.Name);
 }

How can I get Castle to pass the repository into attribute constructor like it does for a controller constructor?


回答1:


You basically have two options. Wrap the filter in a proxy, a good example of this can be found here.

Or, within your custom filter you can do an explicit container call. For example using StructureMap (I have no used castle extensively)

ObjectFactory.GetInstance(IStoryRepository)

There may be a third way which is to extend the ActionInvoker to do the injection but I am not sure how this would be done.




回答2:


The problem is that attributes are constructed by reflection rather than through calls that can be intercepted and replaced with calls that delegate to the container.

There are numerous approaches that can be used to create filters that can support DI, the simplest IMHO is to extend the action invoker and override GetFilters, providing an implementation that uses the attribute to determine the filter type and then resolving that type from the container. An implementation of this approach can be seen in MvcTurbine ( http://mvcturbine.codeplex.com/sourcecontrol/changeset/view/37298?projectName=mvcturbine#758440 ).




回答3:


Why don't you get the IRepository object from a static factory method inside the Filter constructor? You just use the factory method in a way to allow DI to do its work.

DI will work on your "gateway" method instead of the standard "constructor parameter" approach.




回答4:


I might be worth looking at FluentMVC project. It allows you to configure attributes at startup and because it uses windsor under the hood should allow for this to be injected pritty easily. For example

FluentMvcConfiguration.Configure = x => {
                                 x.UsingControllerFactory(new WindsorControllerFactory());                                                                x.WithFilter<HandleErrorAttribute>();
                                 x.WithFilter<AuthorizeAttribute>(
                                     Except
                                         .For<AccountController>(ac => ac.LogOn())
                                         .AndFor<AccountController>(ac => ac.LogOn(null, null, false, null))
                                         .AndFor<HomeController>());
                             };

The code above will add the AuthorizeAttribute to all actions except Login and the home controller

Not sure what the current state of the project is but have used it a few times and works pretty well for me.



来源:https://stackoverflow.com/questions/1292542/how-do-i-pass-in-the-repository-to-an-authorize-attribute-in-asp-net-mvc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!