【发布时间】:2016-04-03 09:19:39
【问题描述】:
我有一个 MVC 项目,我们使用派生自 System.Web.Mvc.AuthorizeAttribute 的自定义属性实现安全性。这放置在我们希望通过派生自System.Web.Mvc.Controller 的 MVC 控制器上的自定义授权来保护的方法上。我们还使用 Autofac for DI (IoC) 将 autohrization 服务注入我们的自定义安全过滤器。
现在,我们还将 Web API 控制器添加到我们的项目中,这些控制器源自 System.Web.Http.ApiController。我遇到的是,当您想在使用 Web API 时在过滤器中包含 DI 时,您似乎必须使用 Autofac DI 使用其流利的 api 注册每个过滤器实例或整个控制器。有关详细信息,请参阅autofac documentation。
对于 MVC 控制器,我们只需添加属性,无需额外注册。 现在对于 ApiControllers,我们需要使用流畅的方法注册该属性(过滤器)实例,不需要将此属性应用于方法/类本身。 我宁愿保持一切一致,更不用说更容易维护,通过将这些过滤器仅作为属性应用而不使用流利的方法。恕我直言,这是一种更简洁的方法,尤其是在可能有 100 多个安全实现的大型解决方案中。
我一直在尝试创建一个方法,该方法将在 Web API 控制器上注册应用过滤器的所有实例,但 Autofac 实现似乎不适合这样做。 任何人都可以建议如何绕过此限制或在运行时注册一次过滤器的替代方法,而不必为每个过滤器实例编写重复的代码?
示例代码
-
ModuleAccessAuthorizationAttribute- 这是实现Autofac.Integration.WebApi.IAutofacAuthorizationFilter的自定义授权属性 -
MyController- 这是一个实现System.Web.Http.ApiController的控制器
这行得通
builder.Register(c => new ModuleAccessAuthorizationAttribute(c.Resolve<IAuthenticationFactory>())) // the constructor actually takes much more information which varies each time it is applied but that is out of the scope of this question
.AsWebApiAuthorizationFilterFor<MyController>(c => c.Get()) // Get() is one of the methods that has needs to have the filter applied to it
.InstancePerRequest();
我想改成这个
public class MyController : ApiController {
[ModuleAccessAuthorizationAttribute]
public IHttpActionResult Get()
}
public static void RegisterWebApiSecurityFilter(ContainerBuilder builder)
{
var securedMembers = typeof(DependencyInjectionConfig).Assembly.ExportedTypes
.Where(x => !x.IsAbstract // not abstract
&& x.Name.EndsWith("Controller", StringComparison.Ordinal) // name ends in controller
&& !x.GetCustomAttributes<ObsoleteAttribute>().Any(y => y.IsError) // not marked as obsolete
&& (x.IsSubclassOf(typeof(System.Web.Http.ApiController)))) // implements ApiController
.SelectMany(x => x.GetMembers(BindingFlags.Public | BindingFlags.Instance)) // public instance members
.Where(x => x.GetCustomAttributes<ModuleAccessAuthorizationAttribute>().Any()) // marked with my custom attribute
.Select(x => x)
.ToList();
foreach (var securedMember in securedMembers) // iterate over collection
{
var attribute = securedMember.GetCustomAttribute<ModuleAccessAuthorizationAttribute>(); // get the attribute instance
var declaringClass = securedMember.DeclaringType; // get the declaring (class) type
builder.Register(c => ModuleAccessAuthorizationAttribute(c.Resolve<IAuthenticationFactory>()))
.AsWebApiAuthorizationFilterFor() // this is where I need help, it seems this is generic only and I cannot explicitly pass in my reflected type declaringClass
.InstancePerRequest();
}
}
【问题讨论】:
标签: c# asp.net-web-api asp.net-web-api2 autofac