gpt4 book ai didi

c# - Autofac Web Api 过滤器 - 在运行时声明

转载 作者:行者123 更新时间:2023-11-30 23:31:41 28 4
gpt4 key购买 nike

我有一个 MVC 项目,我们在其中使用派生自 System.Web.Mvc.AuthorizeAttribute 的自定义属性实现了安全性。这放置在我们希望通过派生自 System.Web.Mvc.Controller 的 MVC Controller 上的自定义授权来保护的方法上。我们还使用 Autofac for DI (IoC) 将自动化服务注入(inject)到我们的自定义安全过滤器中。我们现在还在我们的项目中添加 Web API Controller ,它派生自 System.Web.Http.ApiController。我遇到的问题是,当您想在使用 Web API 时将 DI 包含在过滤器中时,您似乎必须使用 Autofac DI 使用其流畅的 api 注册每个过滤器实例或整个 Controller 。查看autofac documentation了解更多详情。

对于 MVC Controller ,我们只需添加属性,无需额外注册。现在对于 ApiControllers,我们需要使用流畅的方法注册该属性(过滤器)实例,不需要将此属性应用于方法/类本身。我宁愿保持一切一致,更不用说更容易维护,通过仅将这些过滤器作为属性应用而不是使用流畅的方法。恕我直言,这是一种更简洁的方法,尤其是在可能有超过 100 个安全实现的更大的解决方案中。

我一直在尝试创建一个方法来在 Web API Controller 上注册应用过滤器的所有实例,但似乎 Autofac 实现不适合这个。任何人都可以建议如何绕过此限制或在运行时注册一次过滤器而不必为每个过滤器实例编写重复代码的替代方法吗?

示例代码

  • ModuleAccessAuthorizationAttribute - 这是实现 Autofac.Integration.WebApi.IAutofacAuthorizationFilter
  • 的自定义授权属性
  • MyController - 这是一个实现 System.Web.Http.ApiController
  • 的 Controller

这行得通

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();
}
}

最佳答案

不幸的是,AsWebApiAuthorizationFilterFor 的重载没有 controllerType 参数。如果您查看 AsWebApiAuthorizationFilterFor 的源代码方法你可以看到实现如下:

public static IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle>
AsWebApiAuthorizationFilterFor<TController>(this IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle> registration)
where TController : IHttpController
{
return AsFilterFor<IAutofacAuthorizationFilter, TController>(registration, AutofacWebApiFilterProvider.AuthorizationFilterMetadataKey);
}

AsFilterFor 是:

static IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle>
AsFilterFor<TFilter, TController>(IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle> registration, string metadataKey)
where TController : IHttpController
{
if (registration == null) throw new ArgumentNullException("registration");

var limitType = registration.ActivatorData.Activator.LimitType;

if (!limitType.IsAssignableTo<TFilter>())
{
var message = string.Format(CultureInfo.CurrentCulture, RegistrationExtensionsResources.MustBeAssignableToFilterType,
limitType.FullName, typeof(TFilter).FullName);
throw new ArgumentException(message, "registration");
}

var metadata = new FilterMetadata
{
ControllerType = typeof(TController),
FilterScope = FilterScope.Controller,
MethodInfo = null
};

return registration.As<TFilter>().WithMetadata(metadataKey, metadata);
}

有了这些信息,您可以轻松地 fork RegistrationExtensions 类并添加满足您需要的新重载。

即:

public static class MyRegistrationExtensions 
{
public static IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle>
AsWebApiAuthorizationFilterFor(this IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle> registration, Type controllerType)
{
return AsFilterFor<IAutofacAuthorizationFilter>(registration, AutofacWebApiFilterProvider.AuthorizationFilterMetadataKey, controllerType);
}


static IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle>
AsFilterFor<TFilter>(IRegistrationBuilder<object, IConcreteActivatorData, SingleRegistrationStyle> registration, string metadataKey, Type controllerType)
{
if (registration == null) throw new ArgumentNullException("registration");
if (controllerType == null) throw new ArgumentNullException("controllerType");
if (!controllerType.IsAssignableTo<IHttpController>()) throw new ArgumentNullException("controllerType");

var limitType = registration.ActivatorData.Activator.LimitType;

if (!limitType.IsAssignableTo<TFilter>())
{
var message = string.Format(CultureInfo.CurrentCulture, RegistrationExtensionsResources.MustBeAssignableToFilterType,
limitType.FullName, typeof(TFilter).FullName);
throw new ArgumentException(message, "registration");
}

var metadata = new FilterMetadata
{
ControllerType = controllerType,
FilterScope = FilterScope.Controller,
MethodInfo = null
};

return registration.As<TFilter>().WithMetadata(metadataKey, metadata);
}
}

关于c# - Autofac Web Api 过滤器 - 在运行时声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34511916/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com