仅针对一项操作覆盖控制器 AuthorizeAttribute

Posted

技术标签:

【中文标题】仅针对一项操作覆盖控制器 AuthorizeAttribute【英文标题】:Overriding controller AuthorizeAttribute for just one action 【发布时间】:2011-01-05 11:41:46 【问题描述】:

我有一个用 AuthorizeAttribute 装饰的控制器。控制器包含几个都需要身份验证的操作,除了一个需要 CustomAuthorizeAttribute 提供的自定义身份验证的操作。

我的问题是,一旦我在控制器级别添加了 [Authorize],我可以在一个操作上使用 [CustomAuthorize] 覆盖它(或删除它)吗?还是我必须从控制器级别删除 [Authorize] 并将其单独添加到每个其他操作?

我纯粹是为了方便,因为我很懒,不想用 AuthorizeAttribute 装饰每个动作。

[Authorize]
public class MyController : Controller 

  //requires authentication
  public ViewResult Admin() 
    return View();
  

  //... a lot more actions requiring authentication

  //requires custom authentication
  [CustomAuthorize]  //never invoked as already failed at controller level
  public ViewResult Home() 
    return View();
  


【问题讨论】:

懒惰 = 高效 【参考方案1】:

在 MVC 5 中,您可以使用新属性 OverrideAuthorization 覆盖任何操作的授权。基本上,您将其添加到具有与控制器中定义的授权配置不同的授权配置的操作中。

你这样做:

[OverrideAuthorization]
[Authorize(Roles = "Employee")]
public ActionResult List()  ... 

更多信息http://www.c-sharpcorner.com/UploadFile/ff2f08/filter-overrides-in-Asp-Net-mvc-5/

在 ASP.NET Core 2.1 中没有 OverrideAuthorization 属性,您唯一能做的就是使操作匿名,即使控制器不是。更多信息https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1

一种选择是这样做:

[Authorize(Roles = "Admin,Employee")] // admin or employee
public class XController : Controller 

    [Authorize(Roles = "Admin")] // only admin
    public ActionResult ActionX()  ... 

    [AllowAnonymous] // anyone
    public ActionResult ActionX()  ... 

【讨论】:

这很好用,我认为它应该是选定的答案。 Asp.Net Core中是否有类似的东西? 我编辑了答案以添加有关 ASP.NET Core 的信息。 @Sergey 在核心中,您可以像我在示例中说明的那样使其更具限制性,但您不能使用不属于“原始”角色列表的角色覆盖授权。在示例中,我通过只允许 Admin 访问 ActionX 使其更具限制性。这个想法是:如果您必须控制每个操作的授权,那么您应该将不同控制器中的操作分开。 @FranciscoGoldenstein。但对我来说这并不明显,应该明确提及。【参考方案2】:

您可以更改属性运行的顺序(使用 Order 属性),但我相信在这种情况下它们仍然会运行,除非生成立即生效的结果。关键是在***别(类)应用限制最少的属性,并对方法进行更多限制。例如,如果您希望 Home 操作公开可用,则需要从类中删除 Authorize 属性,并将其应用于每个其他方法。

如果操作具有相同的许可级别,但结果不同,则更改顺序可能就足够了。例如,您通常会重定向到 Logon 操作,但对于 Home,您希望重定向到 About 操作。在这种情况下,给类属性Order=2Home 操作属性Order=1

【讨论】:

在这种情况下,CustomAuthorizeAttribute 提供相同级别的访问权限,但用于弥补 Flash 的错误,因此设置 Order 属性足以实现所需的结果。谢谢。 通过对 Action 上的属性进行排序,我能够覆盖 Controller 上的属性。点赞!【参考方案3】:

经过太多时间,我想出了一个解决方案。您需要使用自定义 AuthorizeAttribute 来装饰您的控制器。

public class OverridableAuthorize : AuthorizeAttribute

    public override void OnAuthorization(AuthorizationContext filterContext)
    
        var action = filterContext.ActionDescriptor;
        if(action.IsDefined(typeof(IgnoreAuthorization), true)) return;

        var controller = action.ControllerDescriptor;
        if(controller.IsDefined(typeof(IgnoreAuthorization), true)) return;

        base.OnAuthorization(filterContext);
    

可以在 Action 上与 AllowAnonymous 配对

[AllowAnonymous]

【讨论】:

IgnoreAuthorization?你是说AllowAnonymous AllowAnonymous 是我所需要的。谢谢,@agentfire 是的,我要说的是,AuthorizeAttribute 的 OnAuthorization 方法中已经内置了确切的逻辑......除了它正在寻找的属性是 AllowAnonymous。但是,这很好地说明了如何覆盖它通常应用的严格的“与”逻辑。这样,您可以使用一组参数将 FancyAuthorizeAttribute 类型的属性应用于控制器,然后也将其应用于具有不同参数的单个控制器方法,它的 OnAuthorization 将检测动作级属性并跳过控制器级一。 实际上,别在意我的最后一条评论,这可能行不通。您需要一个单独的类,因为 OnAuhorization 中的逻辑不知道它是针对控制器上的属性还是操作方法运行;在任何一种情况下,他们都会看到 action 方法中存在一个自身的实例,并且他们都会返回而不做任何事情。真可惜。【参考方案4】:

您只需要覆盖控制器中的[Authorize],因为特定操作就是添加

[AllowAnonymous] 

到您不想被授权的操作(然后根据需要添加您的自定义属性)。

查看 cmets/intellisense :

表示一个属性,标记控制器和动作以跳过 授权期间的 System.Web.Mvc.AuthorizeAttribute。

完整示例

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Website

    public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
    
        public void OnAuthorization(AuthorizationFilterContext context)
        
            if (true)//Perform own authorization logic
                return; //simply return if request is authorized

            context.Result = new UnauthorizedResult();
            return; //this is not authorized
        
    

    [Authorize]
    public class WebsiteController : Controller
    
        [HttpGet]
        [AllowAnonymous]//When this is added our Custom Attribute is hit, without it our attribute is not used as request already gets 401 from controller's Authorize
        [CustomAuthorize]
        public IActionResult Index()
        
            return View(new ViewModel());
        

注意

如果您想在您的操作中使用 标准 [Authorize] 属性,这种方法将不起作用,并带有 自定义策略 例如

[Authorize]
public class WebsiteController : Controller

    [HttpGet]
    [AllowAnonymous]
    [Authorize("CustomPolicyName")] //Will not be run
    public IActionResult Index()
    
        return View(new ViewModel());
    



services.AddAuthorization(options =>

    options.AddPolicy("BadgeEntry", policy =>
    policy.RequireAssertion(context =>
        false //Custom logic here
    ));
);

...但是如果您像 OP 一样想要自定义属性,那么您可以使用我的解决方案。

【讨论】:

这个建议很危险(至少对于 asp.net core 3.1)。 AllowAnonymous 还禁用任何以下 Authorize 属性。 @myl ??这正是重点!这就是OP想要做的“覆盖授权属性”。 “危险”是一个见仁见智的问题,可以说将任何网络表单上的任何细节提交到任何服务器都是“危险的”,就像过马路或离开家一样。假设这是一个面向程序员(可能是制作软件)的问答网站,我认为覆盖您帮助编写的应用程序的一部分不会自动被认为过于“危险”。您的评论(和反对票)建议使用 AllowAnonymous 是一个坏主意 - 如果是这样,为什么 MS 发布它!我的回答准确无误。 用户希望使用自定义授权策略。在[AllowAnonymous] 之后添加自定义授权属性没有任何效果,因为[AllowAnonymous] 获胜(尽管有人可能已经猜到了)。 @myl 请查看我的更新(示例代码)。正如您在 OnAuthorization 中的断点所看到的那样,您错了 - 此代码按预期命中。如果在控制器上使用 Authorize,OP 正在询问如何让他们的 custom Authorize 属性 运行单个操作。我的示例代码现在准确地显示了这一点。 注意asp.net核心团队recommends使用“策略设计”来实现自定义授权,但是这个问题具体涉及到一个自定义授权属性 这是不同的,在 asp.net 核心中有很多这种方法的用例。更多信息请参见 Derek Greer ***.com/a/41348219/661584 的出色回答和此处的文档 docs.microsoft.com/en-us/aspnet/core/security/authorization/…【参考方案5】:

在处理原型和生产环境时覆盖所有控制器。

所以不需要移除每个控制器的授权。

app.UseEndpoints(endpoint =>
        
            endpoint.MapControllers().WithMetadata(new AllowAnonymousAttribute());
        );

【讨论】:

以上是关于仅针对一项操作覆盖控制器 AuthorizeAttribute的主要内容,如果未能解决你的问题,请参考以下文章

仅针对某些模型覆盖 Django 管理员 change_list_results.html

如何仅针对 1 个应用程序覆盖 django edit_inline/tabular.html?

Jmeter函数作用域实时取值覆盖[针对HTTP Request等控制器]

tableview 中的多行对用于一行子视图的一项操作作出反应

带有for循环的MVC视图仅返回最后一项

UINavigationController navigationBarHidden 仅针对单个视图控制器设置为 true