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

Posted

技术标签:

【中文标题】在 .net 核心 Web API 中自动添加策略属性【英文标题】:Adding policy attribute automatically in .net core web API 【发布时间】:2019-04-08 12:30:18 【问题描述】:

我正在使用 .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);
        
    

【问题讨论】:

【参考方案1】:

您可以为此使用custom convention,它允许自定义application model。使用约定允许您自动为项目中的每个操作添加过滤器,使用所述约定的全局注册或使用操作上的属性应用它等。

这是一个自定义约定的示例实现,供您参考:

public class SomeActionModelConvention : IActionModelConvention

    public void Apply(ActionModel model)
    
        model.Filters.Add(new AuthorizeFilter(model.ActionName));
    

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

要注册约定,请通过MvcOptions 将其添加到Startup.ConfigureServices。例如:

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

正如我上面所建议的,可以使用属性来注册它,但在这种情况下这没有多大意义,因为您必须将属性添加到操作本身,这会破坏某些东西的目的-level 像这样的约定。

但是,如果您想将其作为 controller 级别的属性应用,以便您可以更有选择性,您可以实现一个自定义 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 的实现以仅添加根据您自己的逻辑进行过滤。因为我已经讲了足够长的时间,所以我不会详细说明。

【讨论】:

感谢您的回复@KirkLarkin。它救了我。你的两个建议都很有效。但是,我无法选择其中之一。我应该更喜欢哪一个?在项目的未来,哪一个是可定制的?你对我的情况有什么想法? 如果我知道控制器中的所有操作都将使用操作名称作为策略名称,我会选择 SomeControllerModelConvention。您可以在每个控制器的基础上应用它(例如,如果某些控制器不需要授权,这很有用),或者,如果您知道它用于项目中的 所有 控制器,则可以如我所述,将其注册为约定。 再次感谢@KirkLarkin。例如 loginController 不需要你说的授权。所以,SomeControllerModelConvention 在这种情况下更有用。

以上是关于在 .net 核心 Web API 中自动添加策略属性的主要内容,如果未能解决你的问题,请参考以下文章

如何在asp.net核心中从客户端调用web api方法?

转如何在Web项目中给没有添加API核心组件添加APIController的帮助页HelpPage

无法在 asp.net 核心中为身份服务器 4 启用 CORS

添加 Authorize 属性时 Web api 核心返回 404

ASP.NET 核心 Web API 和 Angular 客户端中的外部身份验证

如何在Web项目中给没有添加API核心组件添加APIController的帮助页HelpPage