Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding policy attribute automatically in .net core web API

I'm using .net Core 2.1 Web API. I'm using action based authentication. So, I add every method [Authorize(Policy = ".....")] like below. But, I don't want write every time. I want taking policy name from method name automatically. How can I achieve this?

namespace University.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UniversityController : ControllerBase
    {
        private readonly IUniversityService universityService;

        public UniversityController(IUniversityService universityService)
        {
            this.universityService = universityService;
        }

        [Authorize(Policy = "GetUniversities")]
        [HttpGet("GetUniversities")]
        public async Task<ServiceResult> GetUniversities()
        {
            return await universityService.GetUniversities();
        }

        [Authorize(Policy = "GetStudents")]
        [HttpGet("GetStudents")]
        public async Task<ServiceResult> GetStudents()
        {
            return await universityService.GetStudents();
        }

        [Authorize(Policy = "DeleteUniversity")]
        [HttpGet("DeleteUniversity")]
        public async Task<ServiceResult> DeleteUniversity(int universityId)
        {
            return await universityService.DeleteUniversity(universityId);
        }
    }
}
like image 935
realist Avatar asked Nov 05 '18 06:11

realist


People also ask

How do I fix the CORS issue in Web API?

You can enable CORS per action, per controller, or globally for all Web API controllers in your application. To enable CORS for a single action, set the [EnableCors] attribute on the action method. The following example enables CORS for the GetItem method only.

What does ApiController attribute do?

The [ApiController] attribute applies inference rules for the default data sources of action parameters. These rules save you from having to identify binding sources manually by applying attributes to the action parameters.


1 Answers

You can use a custom convention for this, which allows for customisation of the application model. Using a convention allows you to add filters to each action within your project automatically, using either a global registration of said convention or by applying it using a attribute on the action, etc.

Here's a sample implementation of a custom convention for your purposes:

public class SomeActionModelConvention : IActionModelConvention
{
    public void Apply(ActionModel model)
    {
        model.Filters.Add(new AuthorizeFilter(model.ActionName));
    }
}

In this example, we implement IActionModelConvention, which defines an Apply method that is called by the MVC framework on initialisation. In the implementation above, we're simply adding an AuthorizeFilter to the model that uses the action's name as the policy name.

In order to register the convention, add it via MvcOptions in Startup.ConfigureServices. e.g.:

services.AddMvc(options => options.Conventions.Add(new SomeActionModelConvention()));

As I suggested above, it's possible to register this using an attribute, but that doesn't make much sense in this scenario as you'd have to add the attribute to the action itself, which would defeat the purpose of something high-level like this convention.

However, if you want to apply this as an attribute at the controller level so that you can be more selective, you could implement instead a custom controller convention that does something very similar. Here's a sample for that:

public class SomeControllerModelConvention : Attribute, IControllerModelConvention
{
    public void Apply(ControllerModel model)
    {
        foreach (var actionModel in model.Actions)
            actionModel.Filters.Add(new AuthorizeFilter(actionModel.ActionName));
    }
}

This is very similar to SomeActionModelConvention, except for these three differences:

  1. It implements IControllerModelConvention and, as such, is called for each controller rather than for each action.
  2. Apply is handed a ControllerModel, so we iterate through all of its actions and apply the AuthorizeFilter to those.
  3. It extends Attribute so that it can be applied as an attribute.

When using this approach, the convention does not need to be added in Startup.ConfigureServices - instead, it can be added as an attribute. e.g.:

[Route("api/[controller]")]
[ApiController]
[SomeControllerModelConvention]
public class UniversityController : ControllerBase
    ...

Finally, if you want to apply the convention to controllers but do so using code, you could register the convention in Startup.ConfigureServices (as with the SomeActionModelConvention approach) and then customise the implementation of Apply to only add the filter according to your own logic. I won't go into the details of that as I've already gone on for long enough.

like image 59
Kirk Larkin Avatar answered Oct 19 '22 12:10

Kirk Larkin