我使用的是.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);
}
}
}
您可以为此使用自定义约定,从而允许自定义应用程序模型。使用约定可以自动为项目中的每个操作添加过滤器,使用所述约定的全局注册或使用操作上的属性应用它,等等。
以下是针对您的目的的自定义约定的示例实现:
public class SomeActionModelConvention : IActionModelConvention
{
public void Apply(ActionModel model)
{
model.Filters.Add(new AuthorizeFilter(model.ActionName));
}
}
在本例中,我们实现了IActionModelConvention
,它定义了一个Apply
方法,该方法在初始化时由MVC框架调用。在上面的实现中,我们只是将AuthorizeFilter
添加到使用操作名称作为策略名称的模型中。
为了注册约定,请通过Startup.ConfigureServices
中的MvcOptions
将其添加。例如:
services.AddMvc(options => options.Conventions.Add(new SomeActionModelConvention()));
正如我上面所建议的,可以使用属性来注册,但在这种情况下,这没有多大意义,因为你必须将属性添加到动作本身,这将违背像这种约定这样的高级功能的目的。
但是,如果您想将其作为控制器级别的属性应用,以便更具选择性,您可以实现一个自定义的controller约定,该约定可以执行类似的操作。这里有一个例子:
public class SomeControllerModelConvention : Attribute, IControllerModelConvention
{
public void Apply(ControllerModel model)
{
foreach (var actionModel in model.Actions)
actionModel.Filters.Add(new AuthorizeFilter(actionModel.ActionName));
}
}
这与SomeActionModelConvention
非常相似,除了以下三个区别:
- 它实现IControllerModelConvention,因此,它是为每个控制器而不是为每个操作调用的
Apply
得到了一个ControllerModel
,所以我们迭代它的所有操作,并将AuthorizeFilter
应用于这些操作- 它扩展了
Attribute
,使其可以作为属性应用
使用此方法时,公约不需要在Startup.ConfigureServices
中添加,而是可以作为属性添加。例如:
[Route("api/[controller]")]
[ApiController]
[SomeControllerModelConvention]
public class UniversityController : ControllerBase
...
最后,如果您想将约定应用于控制器,但使用代码执行,则可以在Startup.ConfigureServices
中注册约定(与SomeActionModelConvention
方法一样(,然后根据自己的逻辑自定义Apply
的实现以仅添加过滤器。我不会详述,因为我已经讲了足够长的时间了。