Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将AuthorizationPolicy绑定到控制器/操作,而不使用AuthorizationAttribute_C#_Asp.net Core_Authorization_Authorize Attribute - Fatal编程技术网

C# 将AuthorizationPolicy绑定到控制器/操作,而不使用AuthorizationAttribute

C# 将AuthorizationPolicy绑定到控制器/操作,而不使用AuthorizationAttribute,c#,asp.net-core,authorization,authorize-attribute,C#,Asp.net Core,Authorization,Authorize Attribute,我想向.NET核心API添加授权。假设我有一个PersonController,具有以下操作: GetPerson(根据id检索人员) PostPerson(添加一个新人) DeletePerson(删除一个人) 但现在我想将这些策略绑定到控制器操作,以说明执行控制器操作需要哪些策略。我知道这可以通过下面这样的authorizationAttribute来完成:[authorization(Policy=“X”],但我希望能够在不使用authorizationAttribute的情况下完成

我想向.NET核心API添加授权。假设我有一个PersonController,具有以下操作:

  • GetPerson(根据id检索人员)

  • PostPerson(添加一个新人)

  • DeletePerson(删除一个人)

    但现在我想将这些策略绑定到控制器操作,以说明执行控制器操作需要哪些策略。我知道这可以通过下面这样的authorizationAttribute来完成:
    [authorization(Policy=“X”]
    ,但我希望能够在不使用authorizationAttribute的情况下完成

    为什么我不能使用[授权]属性?
    我不会说得太详细,但是控制器的源代码已经生成。这意味着所有手动更改都将在再次生成后被覆盖。因此,授权不应该在控制器中

    在startup.cs中,我将控制器映射到端点,如下所示:

    app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    
    endpoints.MapControllers().RequireAuthorization("SuperAdmin");
    
    // pseudo-code  
    // endpoints.MapControllerAction("GetPerson").RequireAuthorization("SuperAdmin", "PersonReader");
    
    public static class AuthorizeAttributeInjectionMvcOptionsExtensions
    {
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, params AuthorizeAttribute[] authorizeAttributes)
        {
            return options.ApplyAuthorizeAttributes(controllerName, null, authorizeAttributes);
        }
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, string actionName, params AuthorizeAttribute[] authorizeAttributes)
        {
            options.Conventions.Add(new AuthorizeAttributeInjectingConvention(controllerName, actionName, authorizeAttributes));
            return options;
        }
        public static MvcOptions ApplyAuthorizationPolicy(this MvcOptions options, string controllerName, string actionName, params string[] policies)
        {
            return options.ApplyAuthorizeAttributes(controllerName, actionName, policies.Select(e => new AuthorizeAttribute(e)).ToArray());
        }        
    }
    
    services.AddMvc(o => {
        //...
    
        //by AuthorizeAttribute
        var withSuperAdminAttr = new AuthorizeAttribute("SuperAdmin");
        o.ApplyAuthorizeAttributes("your_controller", "your_action", withSuperAdminAttr);
    
        //by policy
        o.ApplyAuthorizationPolicy("your_controller", "your_action", "SuperAdmin");
        //...
    });
    
    可以为所有控制器绑定一个策略,如下所示:

    app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    
    endpoints.MapControllers().RequireAuthorization("SuperAdmin");
    
    // pseudo-code  
    // endpoints.MapControllerAction("GetPerson").RequireAuthorization("SuperAdmin", "PersonReader");
    
    public static class AuthorizeAttributeInjectionMvcOptionsExtensions
    {
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, params AuthorizeAttribute[] authorizeAttributes)
        {
            return options.ApplyAuthorizeAttributes(controllerName, null, authorizeAttributes);
        }
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, string actionName, params AuthorizeAttribute[] authorizeAttributes)
        {
            options.Conventions.Add(new AuthorizeAttributeInjectingConvention(controllerName, actionName, authorizeAttributes));
            return options;
        }
        public static MvcOptions ApplyAuthorizationPolicy(this MvcOptions options, string controllerName, string actionName, params string[] policies)
        {
            return options.ApplyAuthorizeAttributes(controllerName, actionName, policies.Select(e => new AuthorizeAttribute(e)).ToArray());
        }        
    }
    
    services.AddMvc(o => {
        //...
    
        //by AuthorizeAttribute
        var withSuperAdminAttr = new AuthorizeAttribute("SuperAdmin");
        o.ApplyAuthorizeAttributes("your_controller", "your_action", withSuperAdminAttr);
    
        //by policy
        o.ApplyAuthorizationPolicy("your_controller", "your_action", "SuperAdmin");
        //...
    });
    
    但这意味着我将要求所有控制器操作使用“超级管理员”策略。因此,我无法定义特定操作所需的策略。我希望这样做:

    app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    
    endpoints.MapControllers().RequireAuthorization("SuperAdmin");
    
    // pseudo-code  
    // endpoints.MapControllerAction("GetPerson").RequireAuthorization("SuperAdmin", "PersonReader");
    
    public static class AuthorizeAttributeInjectionMvcOptionsExtensions
    {
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, params AuthorizeAttribute[] authorizeAttributes)
        {
            return options.ApplyAuthorizeAttributes(controllerName, null, authorizeAttributes);
        }
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, string actionName, params AuthorizeAttribute[] authorizeAttributes)
        {
            options.Conventions.Add(new AuthorizeAttributeInjectingConvention(controllerName, actionName, authorizeAttributes));
            return options;
        }
        public static MvcOptions ApplyAuthorizationPolicy(this MvcOptions options, string controllerName, string actionName, params string[] policies)
        {
            return options.ApplyAuthorizeAttributes(controllerName, actionName, policies.Select(e => new AuthorizeAttribute(e)).ToArray());
        }        
    }
    
    services.AddMvc(o => {
        //...
    
        //by AuthorizeAttribute
        var withSuperAdminAttr = new AuthorizeAttribute("SuperAdmin");
        o.ApplyAuthorizeAttributes("your_controller", "your_action", withSuperAdminAttr);
    
        //by policy
        o.ApplyAuthorizationPolicy("your_controller", "your_action", "SuperAdmin");
        //...
    });
    

    很遗憾,我找不到任何方法来执行此操作。是否有方法可以在不使用[Authorize]的情况下将策略绑定到控制器操作属性?

    您可以通过应用程序模型约定
    iaapplicationmodelconvention
    以编程方式应用
    AuthorizeAttribute
    或任何其他类型的属性。在那里,您可以访问根
    ApplicationModel
    ,其中包含所有加载的控制器,并且可以添加
    AuthorizeAttribute
    在那里。每个控制器都由一个名为
    ControllerModel
    的类表示。它实现了
    IFilterModel
    ,该类公开了
    IFilterMetadata
    的列表。该模型还实现了
    ICommonModel
    ,该类公开了属性列表,但该列表是只读的。因此,要修改该列表,您可能需要创建一个新模型来覆盖旧模型,这相当复杂。每个操作都由
    ActionModel
    表示,它还实现了
    IFilterModel
    。因此在这种情况下,我们不尝试通过将
    AuthorizeAttribute
    添加到属性列表来应用它,而是将其转换为
    AuthorizeFilter
    也是一个
    IFilterMetadata
    ,因此可以将其添加到
    IFilterModel
    公开的筛选器列表中

    详细代码如下:

    public class AuthorizeAttributeInjectingConvention : IApplicationModelConvention
    {
        readonly string _controller;
        readonly string _action;
        readonly AuthorizeFilter[] _authorizeFilters;
        public AuthorizeAttributeInjectingConvention(string controllerName, params AuthorizeAttribute[] authorizeAttributes) 
            : this(controllerName, null, authorizeAttributes)
        {                  
        }
        public AuthorizeAttributeInjectingConvention(string controllerName, string actionName, params AuthorizeAttribute[] authorizeAttributes)
        {
            _controller = controllerName;
            _action = actionName;
            _authorizeFilters = authorizeAttributes.Select(e => new AuthorizeFilter(new[] { e })).ToArray();
        }
    
        public void Apply(ApplicationModel application)
        {
            var filterModels = application.Controllers
                                         .Where(e => string.Equals(e.ControllerName, _controller, StringComparison.OrdinalIgnoreCase))
                                         .ToList<IFilterModel>();
            if(filterModels.Count > 0 && !string.IsNullOrWhiteSpace(_action))
            {
                filterModels = filterModels.Cast<ControllerModel>()
                                           .SelectMany(e => e.Actions.Where(o => string.Equals(o.ActionName, _action, StringComparison.OrdinalIgnoreCase)))
                                           .ToList<IFilterModel>();
            }
            foreach(var filterModel in filterModels)
            {                
                foreach(var af in _authorizeFilters)
                {
                    filterModel.Filters.Add(af);
                }
            }
        }
    }
    
    现在在
    Startup.ConfigureServices
    中,您可以将所选的
    authorized属性
    应用于特定的控制器或操作(通过其名称),如下所示:

    app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    
    endpoints.MapControllers().RequireAuthorization("SuperAdmin");
    
    // pseudo-code  
    // endpoints.MapControllerAction("GetPerson").RequireAuthorization("SuperAdmin", "PersonReader");
    
    public static class AuthorizeAttributeInjectionMvcOptionsExtensions
    {
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, params AuthorizeAttribute[] authorizeAttributes)
        {
            return options.ApplyAuthorizeAttributes(controllerName, null, authorizeAttributes);
        }
        public static MvcOptions ApplyAuthorizeAttributes(this MvcOptions options, string controllerName, string actionName, params AuthorizeAttribute[] authorizeAttributes)
        {
            options.Conventions.Add(new AuthorizeAttributeInjectingConvention(controllerName, actionName, authorizeAttributes));
            return options;
        }
        public static MvcOptions ApplyAuthorizationPolicy(this MvcOptions options, string controllerName, string actionName, params string[] policies)
        {
            return options.ApplyAuthorizeAttributes(controllerName, actionName, policies.Select(e => new AuthorizeAttribute(e)).ToArray());
        }        
    }
    
    services.AddMvc(o => {
        //...
    
        //by AuthorizeAttribute
        var withSuperAdminAttr = new AuthorizeAttribute("SuperAdmin");
        o.ApplyAuthorizeAttributes("your_controller", "your_action", withSuperAdminAttr);
    
        //by policy
        o.ApplyAuthorizationPolicy("your_controller", "your_action", "SuperAdmin");
        //...
    });
    
    请注意,上面的代码并不完美,它介绍了如何基本上实现它。您可以进一步改进的逻辑是如何筛选目标控制器和操作。在我的示例中,它只是根据控制器名称和操作名称进行筛选。我认为,只要您有唯一的控制器名称和uniqu,这几乎在任何情况下都会起作用e操作名称。否则,在实际应用
    authorized属性之前,您可能必须添加更多自定义逻辑以针对正确的控制器和操作