在.net Core Web API中自动添加策略属性

rea*_*ist 4 c# asp.net-core asp.net-core-webapi asp.net-core-2.1

我正在使用.net Core 2.1 Web API。我正在使用基于操作的身份验证。因此,我添加了[Authorize(Policy = ".....")]如下所示的每种方法。但是,我不想每次都写。我想从方法名称中自动获取策略名称。我该如何实现?

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Kir*_*kin 6

您可以为此使用自定义约定,该约定允许对应用程序模型进行自定义。通过使用约定,您可以使用该约定的全局注册或通过在动作上使用属性等将其自动添加到项目中每个动作的过滤器。

这是您自定义约定的示例实现:

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

在此示例中,我们实现IActionModelConvention,该Apply方法定义了MVC框架在初始化时调用的方法。在上面的实现中,我们只是向AuthorizeFilter使用动作名称作为策略名称的模型添加一个。

为了注册该约定,请通过MvcOptions在中添加它Startup.ConfigureServices。例如:

serices.AddMvc(options => options.Conventions.Add(new SomeActionModelConvention()));
Run Code Online (Sandbox Code Playgroud)

正如我上面所建议的,可以使用属性来注册该属性,但是在这种情况下这没有多大意义,因为您必须将该属性添加到动作本身,这会破坏诸如这个约定。

但是,如果要将此属性作为属性应用于控制器级别,以便更具选择性,则可以改用实现类似功能的自定义控制器约定。这是一个示例:

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

SomeActionModelConvention除了这三个差异之外,这与十分相似:

  1. 它实现了IControllerModelConvention,因此,它是为每个控制器而不是每个动作调用的。
  2. Apply传递给ControllerModel,因此我们迭代其所有动作并将其应用于AuthorizeFilter这些动作。
  3. 它进行扩展,Attribute以便可以将其用作属性。

使用此方法时,公约并没有需要添加Startup.ConfigureServices-相反,它可以作为一个属性。例如:

[Route("api/[controller]")]
[ApiController]
[SomeControllerModelConvention]
public class UniversityController : ControllerBase
    ...
Run Code Online (Sandbox Code Playgroud)

最后,如果您想将约定应用于控制器,但使用代码来执行,则可以在中注册约定Startup.ConfigureServices(与SomeActionModelConvention方法一样),然后自定义实现Apply以仅根据自己的逻辑添加过滤器。由于已经进行了足够长的时间,因此我将不再赘述。