如何在ASP.NET Core中使用IAsyncAuthorizationFilter实现依赖注入

5

我已经将 IAsyncAuthorizationFilter 接口实现到一个类中;此外,该类派生自 Attribute,因此我可以标记控制器类和操作方法。目前为止,这个方法是有效的;在调用操作方法之前,会调用 Task OnAuthorizationAsync(AuthorizationFilterContext context) 方法,如果请求未经过身份验证,则返回响应的 HTTP 401

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class CustomAuthenticationAttribute : Attribute, IAsyncAuthorizationFilter 
{
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        ...
    }
}

此属性的使用方法如下...

[CustomAuthenticationAttribute]
public class SomeDataController : Controller
{
    [HttpGet]
    public async Task GetData()
    {
        ...
    }
}

现在,我想使用一个应用程序服务(从数据库中获取身份验证所需的秘密私钥信息),并尝试使用属性注入来实现。由于它是作为属性实现的,因此通过构造函数注入依赖项不是一个好选择。所以我尝试了...

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class CustomAuthenticationAttribute : Attribute, IAsyncAuthorizationFilter 
{
    public IPrivateKeyLookupService KeyService { get; set; }

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        string publicKey = ...
        ...
        var privateKey = await this.KeyService.GetPrivateKeyFrom(publicKey);
        ...
    }
}

...但是属性注入似乎在这里不起作用。该服务已在IoC中注册,但属性未被连接。这是一个ASP.NET Core 1.1项目,我使用Autofac。在Startup类中,我的ConfigureServices方法有以下代码...

public void ConfigureServices(IServicesCollection collection)
{
    ...

    var containerBuilder = new ContainerBuilder();
    containerBuilder.RegisterType<AuthKeyService>().As<IPrivateKeyLookupService>();

    containerBuilder.Populate(services);

    this.container = containerBuilder.Build();
}
< p >Autofac是否支持IAsyncAuthorizationFilter类型的自动装配?如果不支持,我该如何实现该功能?

你尝试过使用[TypeFilter(typeof(CustomAuthenticationAttribute))]在控制器上注册你的过滤器吗?你可以在这里获取更多信息:https://joonasw.net/view/aspnet-core-di-deep-dive - juunas
@juunas 谢谢;我几分钟前才找到那个解决方案。这很典型...我找了好几个小时,然后在我问问题之后,解决方案就出现了 (-; - Matze
2个回答

16

结果证明这非常简单...

ASP.NET Core中,有一个名为TypeFilter的属性,它也是一个过滤器,可以创建另一个过滤器(由Type指定),并通过依赖注入来满足其构造函数参数。

我改变了IAsyncAuthorizationFilter的实现方法;移除了属性并添加了一个ctor,因为现在使用TypeFilter的ctor注入可以工作了...

public sealed class CustomAuthenticationAttribute : IAsyncAuthorizationFilter 
{
    private readonly IPrivateKeyLookupService keyService;
    public CustomAuthenticationAttribute(
        IPrivateKeyLookupService keyService)
    {
        this.keyService = keyService;
    }

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        ...
    }
}

我也从Attribute中移除了继承,因为它不再需要,同时取消了AttributeUsage属性的声明。

这样,我就可以像下面这样使用我的属性...

[TypeFilter(typeof(CustomAuthenticationAttribute))]
public class SomeDataController : Controller
{
    [HttpGet]
    public async Task GetData()
    {
        ...
    }
} 

通过 TypeFilter 类的 object[] Arguments 属性,可以向过滤器的构造函数传递其他参数。


非常棒。这绝对是检查 API 密钥的简单方法。 - Yehuda Makarov
干得好!这只是依赖注入中必须跳过的又一个例子,但还是谢谢你分享 :) - Jimbo

3

通常需要做的事情是获取以前注册的ISomething,特别是当您在HTTP管道的任何位置实现自定义属性时。

基本上,您需要获取HttpContext并使用HttpContext.RequestServices中定位的IServiceProvider。

从那里开始,如果您已经包含了所需程序集,一切都很容易。

using Microsoft.Extensions.DependencyInjection;

让我在一个小样本中演示一下,我将获取已注册的IMemoryCache(当然,您需要通过在startup.cs中添加services.AddMemoryCache()来注册它才能使其正常工作)。

以下是复制粘贴的内容:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;

using Microsoft.Extensions.DependencyInjection;

public class SomeAttribute : Attribute,IAuthorizationFilter
{        
    public void OnAuthorization(AuthorizationFilterContext context )
    {
        IMemoryCache memory= context.HttpContext.RequestServices.GetService<IMemoryCache>();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接