You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在自定义AuthorizeFilter Attribute中用Autofac解析依赖供ApiController使用?

在自定义AuthorizeAttribute中使用Autofac解析依赖

当然可以在自定义AuthorizeAttribute里通过Autofac解析依赖!不过要注意:AuthorizeAttribute是由.NET框架直接实例化的,不属于Autofac的管理范畴,所以没法直接用构造函数注入依赖。不过我们可以从请求上下文里拿到Autofac的请求作用域,进而解析需要的服务。

结合你的代码,我给你调整出具体的实现方案:

1. 修改自定义Authorization Attribute

我们需要从HttpActionContext中获取Autofac的依赖作用域,然后解析IMyAccessHelper(建议把你的myAccessHelper抽象成接口,符合依赖倒置原则):

public class CustomAuthorizationFilterAttribute : AuthorizeAttribute
{
    private const string REQUEST_KEY_USERACCESS = "UserAccess";

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        try
        {
            // 从请求上下文获取Autofac的请求级依赖作用域
            var dependencyScope = actionContext.Request.GetDependencyScope();
            var myAccessHelper = dependencyScope.GetService(typeof(IMyAccessHelper)) as IMyAccessHelper;

            // 安全获取Authorization Token,避免空引用
            var token = actionContext.Request.Headers.Authorization?.Parameter;
            if (string.IsNullOrWhiteSpace(token))
            {
                return false;
            }

            MyUserAccess userAccess = myAccessHelper.GetUserAccess(token);
            actionContext.Request.Properties.Add(REQUEST_KEY_USERACCESS, userAccess);
            return true;
        }
        catch (Exception ex)
        {
            // 这里建议添加日志记录,方便排查问题
            // _logger.LogError(ex, "Authorization failed");
            return false;
        }
    }
}

2. 确保依赖已注册到Autofac

在你的Autofac容器配置中,要把IMyAccessHelper和对应的实现类注册为请求级实例(因为每个请求的上下文是独立的):

var builder = new ContainerBuilder();

// 注册Web API控制器
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

// 注册你的访问助手,请求级生命周期
builder.RegisterType<MyAccessHelper>().As<IMyAccessHelper>().InstancePerRequest();

// 注册委托工厂(你原来的代码已经在用,这里保持不变)
builder.RegisterType<ServiceData>().AsSelf();
builder.RegisterGeneratedFactory<ServiceData.Factory>();

var container = builder.Build();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

3. 优化控制器中的代码

你原来的控制器代码可以稍微优化一下,让类型转换更安全简洁:

public class MyController : ApiController
{
    private readonly ServiceData.Factory _myServiceFactory;

    public MyController(ServiceData.Factory myServiceFactory)
    {
        _myServiceFactory = myServiceFactory;
    }

    public IHttpActionResult GetData([FromUri] MyFilter filter)
    {
        if (Request.Properties.TryGetValue("UserAccess", out var userAccessObj) && userAccessObj is MyUserAccess userAccess)
        {
            var myService = _myServiceFactory.Invoke(userAccess);
            return Ok(myService.GetSomething());
        }
        return Content(HttpStatusCode.Forbidden, "No User Access");
    }
}

额外的优雅方案:使用Autofac管理过滤器生命周期

如果你的过滤器依赖较多,或者想更贴合Autofac的依赖注入理念,可以不用继承AuthorizeAttribute,而是实现IAuthorizationFilter接口,然后通过自定义IFilterProvider让Autofac来管理过滤器的实例化:

  1. 创建一个依赖注入的过滤器:
public class CustomAuthorizationFilter : IAuthorizationFilter
{
    private readonly IMyAccessHelper _myAccessHelper;

    // 直接构造函数注入依赖
    public CustomAuthorizationFilter(IMyAccessHelper myAccessHelper)
    {
        _myAccessHelper = myAccessHelper;
    }

    public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
    {
        try
        {
            var token = actionContext.Request.Headers.Authorization?.Parameter;
            if (string.IsNullOrWhiteSpace(token))
            {
                return Task.FromResult(actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized));
            }

            var userAccess = _myAccessHelper.GetUserAccess(token);
            actionContext.Request.Properties.Add("UserAccess", userAccess);
            return continuation();
        }
        catch (Exception)
        {
            return Task.FromResult(actionContext.Request.CreateResponse(HttpStatusCode.Forbidden));
        }
    }

    public bool AllowMultiple => false;
}
  1. 注册自定义过滤器提供程序:
public class AutofacFilterProvider : ActionDescriptorFilterProvider, IFilterProvider
{
    private readonly IComponentContext _container;

    public AutofacFilterProvider(IComponentContext container)
    {
        _container = container;
    }

    public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(configuration, actionDescriptor);
        foreach (var filter in filters)
        {
            _container.InjectProperties(filter.Instance);
        }
        // 这里可以添加全局过滤器,或者按条件注册过滤器
        filters = filters.Concat(new[] { new FilterInfo(_container.Resolve<CustomAuthorizationFilter>(), FilterScope.Global) });
        return filters;
    }
}
  1. 在容器配置中替换默认的过滤器提供程序:
var builder = new ContainerBuilder();
// ... 其他注册代码 ...
builder.RegisterType<AutofacFilterProvider>().As<IFilterProvider>().SingleInstance();

var container = builder.Build();
var config = GlobalConfiguration.Configuration;
config.Services.Replace(typeof(IFilterProvider), container.Resolve<AutofacFilterProvider>());
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

这个方案更适合复杂场景,能充分利用Autofac的生命周期管理和依赖注入能力。


内容的提问来源于stack exchange,提问作者zeroflaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:49:13