简体   繁体   中英

How to get dependency injection working with IAsyncAuthorizationFilter in ASP.NET Core

I have implemented the IAsyncAuthorizationFilter interface to a class; in addition, that class is derived from Attribute , so that I can mark controller classes and action methods using it. This works so far; the Task OnAuthorizationAsync(AuthorizationFilterContext context) method is called before the action method, and if the request is not authenticated, an HTTP 401 is returned for the response.

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

This attribute is used as follows...

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

Now, I want to use an application service (which obtains secret private key information required for authentication from a database) and tried to use property injection for that. Injecting dependencies via the ctor is not a good choice here since it´s implemented as an attribute. So I tried...

[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);
        ...
    }
}

...but property injection does not seem to work here. The service is registered with the IoC, but properties do not get wired. This is an ASP.NET Core 1.1 project in which I use Autofac . In the Startup class my ConfigureServices method has something like that...

public void ConfigureServices(IServicesCollection collection)
{
    ...

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

    containerBuilder.Populate(services);

    this.container = containerBuilder.Build();
}

Does Autofac support auto-wiring for IAsyncAuthorizationFilter types? And if not, how could I polyfill that functionality?

It turned out to be very simple...

In ASP.NET Core there is the TypeFilter attribute which is also a filter that creates another filter (specified by Type ) and satisfies its constructor arguments by involving dependency injection.

I changed the implementation of IAsyncAuthorizationFilter ; removed the properties and added a ctor instead, because with TypeFilter ctor injection would work now...

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

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

I also removed inheritance from Attribute because it´s not needed anymore as well as the declaration of the AttributeUsage attribute.

So, I can use my attribute as follows...

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

Passing additional arguments to the filter´s ctor is also possible via the object[] Arguments property of the TypeFilter class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM