Recently I needed to have a custom authorization attribute to use in my .NET API, where I needed to have some dependency injected services but also pass in an argument to the attribute. I hope this can help you:
enum Feature
{
Articles,
Comments
}
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
// Instead of an enum you can use any other type you want, in my case I had a predefined
// list of features I wanted to authorize against.
public CustomAuthorizeAttribute(Feature feature) : base(typeof(CustomAuthorizeFilter))
{
Arguments = new object[] { feature };
}
}
public class CustomAuthorizeFilter : IAuthorizationFilter
{
private readonly IServiceA _serviceA;
private readonly Feature _feature;
public CustomAuthorizeFilter(Feature feature, IServiceA serviceA)
{
_feature = feature;
_serviceA = serviceA;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
// Here the _feature passed in from the usage of the attribute will be available.
// You can also use the service(s) you injected.
}
}
Then we must register the required services for dependency injection.
builder.Services.AddScoped<IServiceA, ServiceA>();
builder.Services.AddScoped<CustomAuthorizeAttribute>();
Finally you can use the attribute in your controller(s).
[ApiController]
public class CommentsController : ControllerBase
{
[CustomAuthorize(Feature.Comments)]
[HttpPost]
public async Task<IActionResult> AddComment()
{
// ...
}
}
You can also specify a default value for your parameter so you don't have to pass one each time:
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
// Instead of an enum you can use any other type you want, in my case I had a predefined
// list of features I wanted to authorize against.
public CustomAuthorizeAttribute(Feature feature = Feature.Comments) : base(typeof(CustomAuthorizeFilter))
{
Arguments = new object[] { feature };
}
}
[ApiController]
public class CommentsController : ControllerBase
{
[CustomAuthorize]
[HttpPost]
public async Task<IActionResult> AddComment()
{
// ...
}
}