asp.net-mvc Asp.net MVC4:对控制器和动作进行授权

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16709853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 02:52:23  来源:igfitidea点击:

Asp.net MVC4: Authorize on both controller and action

asp.net-mvcauthorize-attribute

提问by frank

If I have the Authorize attribute on both the controller and the action, which one will take the effect? Or will both take effect?

如果我在控制器和动作上都有 Authorize 属性,哪个会生效?还是两者都会生效?

回答by Andy Brown

You asked:

你问:

If I have Authorize attribute on both controller and action, which one will take the effect? Both?

如果我在控制器和动作上都有 Authorize 属性,哪个会生效?两个都?

To answer this simply: Both. The effect is to ANDthe two restrictions together. I'll explain why below ...

简单地回答这个问题:两者都有。效果就是把AND两个限制放在一起。我将在下面解释为什么...

Details

细节

So, there are a few reasons you could be asking this.

因此,您可能会问这个问题有几个原因。

  1. You want to know how to enforce an additional constraint on an Action compared to a method. e.g.
    • At controller level, enforce users in the role "user"
    • At an action level, additionally enforce users in the role "admin"
  2. You want to replace the controller constraint at the action level
  3. You want to remove the controller constraint at the action level and make the method available to anonymous users
  1. 与方法相比,您想知道如何对 Action 实施额外的约束。例如
    • 在控制器级别,强制用户扮演“用户”角色
    • 在操作级别,另外强制用户扮演“管理员”角色
  2. 您想在操作级别替换控制器约束
  3. 您想在操作级别删除控制器约束并使匿名用户可以使用该方法

You didn't specify your MVC version, so I will assume the latest as of today (MVC 4.5). However, that won't change of the answer much even if you were using MVC 3.

您没有指定您的 MVC 版本,因此我将假定为今天的最新版本(MVC 4.5)。但是,即使您使用的是 MVC 3,这也不会改变答案。

[Anonymous]overrides controller [Authorize](case 3)

[Anonymous]覆盖控制器[Authorize](情况 3)

Case 3. I don't need to cover (the use of [AllowAnonymous]) as it has been answered all over SOand all over the webalready. Suffice to say: if you specify [AllowAnonymous]on an action it will make that action public even if the controller has [Authorize]on it.

案例 3. 我不需要覆盖(使用[AllowAnonymous]),因为它已经在 SO整个网络上得到了回答。我只想说:如果你指定[AllowAnonymous]一个动作,即使控制器已经[Authorize]在它上面,它也会使该动作公开。

You can also make an entire website subject to authorisation by using a global filter, and use AllowAnonymouson the few actions or controllers you want to make public.

您还可以使用全局过滤器使整个网站都受到授权,并AllowAnonymous在您想要公开的少数操作或控制器上使用。

[Authorize]is additive (case 1)

[Authorize]是可加的(情况 1)

Case 1 is easy. Take the following controller as an example:

情况 1 很简单。以下面的控制器为例:

[Authorize(Roles="user")]
public class HomeController : Controller {
    public ActionResult AllUsersIndex() {
        return View();
    }

    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
}

By default [Authorize(Roles="user")]makes all Actions in the Controller available to accounts in the "user" role only. Therefore to access AllUsersIndexyou must be in the "user" role. However to access AdminUsersIndexyou must be both in the "user" and the "admin" role. For example:

默认情况下[Authorize(Roles="user")],控制器中的所有操作仅可用于“用户”角色中的帐户。因此,要访问AllUsersIndex您必须是“用户”角色。但是要访问AdminUsersIndex您必须同时处于“用户”和“管理员”角色。例如:

  • UserName: Bob, Roles: user, cannotaccess AdminUsersIndex, but can access AllUsersIndex
  • UserName: Jane, Roles: admin, cannotaccess AdminUsersIndexor AllUsersIndex
  • UserName: Tim, Roles: user & admin, canaccess AdminUsersIndexand AllUsersIndex
  • 用户名:鲍勃,角色:用户,不能访问AdminUsersIndex,但可以访问AllUsersIndex
  • 用户名:Jane,角色:admin,无法访问AdminUsersIndexAllUsersIndex
  • 用户名:Tim,角色:用户和管理员,可以访问AdminUsersIndexAllUsersIndex

This illustrates that the [Authorize]attribute is additive. This is also true of the Usersproperty of the attribute, which can be combined with Rolesto make it even more restrictive.

这说明该[Authorize]属性是可加的。Users属性的属性也是如此,可以将其与 结合起来Roles使其更具限制性。

This behaviour is due to the way that controller and action attributes work. The attributes are chained together and applied in the order controller then action. If the first one refuses authorization, then control returns and the action's attribute is not called. If the first one passes authorization, then the second one is then checked as well. You can override this order by specifying Order(for example [Authorize(Roles = "user", Order = 2)]).

这种行为是由于控制器和动作属性的工作方式造成的。属性链接在一起并应用在订单控制器然后是动作中。如果第一个拒绝授权,则控制返回并且不调用动作的属性。如果第一个通过授权,那么第二个也会被检查。您可以通过指定Order(例如[Authorize(Roles = "user", Order = 2)])来覆盖此顺序。

Overriding [Authorize](case 2)

覆盖[Authorize](案例 2)

Case 2 is trickier. Recall from above that the [Authorize]attributes are examined in the order (Global then) Controller then Action. The first one to detect that the user is ineligible to be authorized wins, the others don't get called.

情况 2 比较棘手。回想一下,[Authorize]按照(全局然后)控制器然后操作的顺序检查属性。第一个检测到用户没有资格获得授权的人获胜,其他人不会被调用。

One way around this is to define two new attributes as below. The [OverrideAuthorize]does nothing other than defer to [Authorize]; its only purpose is to define a type that we can check for. The [DefaultAuthorize]allows us to check to see if the Action being called in the request is decorated with a [OverrideAuthorize]. If it is then we defer to the Action authorization check, otherwise we proceed with the Controller level check.

解决此问题的一种方法是定义两个新属性,如下所示。该[OverrideAuthorize]做无非延迟到其他[Authorize]; 它的唯一目的是定义一个我们可以检查的类型。将[DefaultAuthorize]允许我们检查,看看是否调用请求的作用进行装饰着[OverrideAuthorize]。如果是,那么我们将遵循 Action 授权检查,否则我们继续进行 Controller 级别检查。

public class DefaultAuthorizeAttribute : AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var action = filterContext.ActionDescriptor;
        if (action.IsDefined(typeof(OverrideAuthorizeAttribute), true)) return;

        base.OnAuthorization(filterContext);
    }
}
public class OverrideAuthorizeAttribute : AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
    }
}

We can then use it like this:

然后我们可以像这样使用它:

[DefaultAuthorize(Roles="user")]
public class HomeController : Controller {
    // Available to accounts in the "user" role
    public ActionResult AllUsersIndex() {
        return View();
    }
    // Available only to accounts both in the "user" and "admin" role
    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
    // Available to accounts in the "superuser" role even if not in "user" role
    [OverrideAuthorize(Roles = "superuser")]
    public ActionResult SuperusersIndex() {
        return View();
    }
}

In the above example SuperusersIndexis available to an account that has the "superuser" role, even if it does not have the "user" role.

在上面的示例SuperusersIndex中,具有“超级用户”角色的帐户可以使用,即使它没有“用户”角色。

回答by Akodo_Shado

I would like to add something to Overriding [Authorize] (case 2)

我想向 Overriding [Authorize] 添加一些内容(案例 2)

OverrideAuthorizeAttribute and DefaultAuthorizeAttribute works fine, but I discover that you can also use OverrideAuthorizationAttribute which overrides authorization filters defined at a higher level.

OverrideAuthorizeAttribute 和 DefaultAuthorizeAttribute 工作正常,但我发现您还可以使用 OverrideAuthorizationAttribute 来覆盖在更高级别定义的授权过滤器。

[Authorize(Roles="user")]
public class HomeController : Controller {
    // Available to accounts in the "user" role
    public ActionResult AllUsersIndex() {
        return View();
    }
    // Available only to accounts both in the "user" and "admin" role
    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
    // Available to accounts in the "superuser" role even if not in "user" role
    [OverrideAuthorization()]
    [Authorize(Roles = "superuser")]
    public ActionResult SuperusersIndex() {
        return View();
    }
}

回答by Jo Ham

I made an adaptation of this answer's second casefor ASP.NET Core 2.1.

我为 ASP.NET Core 2.1改编了这个答案的第二个案例

The difference with ASP.NET Core's AuthorizeAttributeis that you don't have to call AuthorizeAttribute.OnAuthorizationbase method to proceed to normal authorization. This means that even if you don't explicitly call the base method, the base AuthorizeAttributecould still short-circuit authorization by forbidding access.

与 ASP.NET Core 的不同之处AuthorizeAttribute在于,您不必调用AuthorizeAttribute.OnAuthorization基本方法即可进行正常授权。这意味着即使您没有显式调用 base 方法,baseAuthorizeAttribute仍然可以通过禁止访问来短路授权。

What I did is that I created a DefaultAuthorizeAttributethat does not inherit from AuthorizeAttribute, but from Attributeinstead. Since the DefaultAuthorizeAttributedoes not inherit from AuthorizeAttribute, I had to recreate the authorization behavior.

我所做的是我创建了一个DefaultAuthorizeAttribute不继承自AuthorizeAttribute,而是继承自Attribute。由于DefaultAuthorizeAttribute不继承自AuthorizeAttribute,我不得不重新创建授权行为。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class DefaultAuthorizeAttribute : Attribute, IAuthorizationFilter
{
    private readonly AuthorizeFilter m_authorizeFilter;

    public DefaultAuthorizeAttribute(params string[] authenticationSchemes)
    {
        var policyBuilder = new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes(authenticationSchemes)
            .RequireAuthenticatedUser();
        m_authorizeFilter = new AuthorizeFilter(policyBuilder.Build());
    }

    public void OnAuthorization(AuthorizationFilterContext filterContext)
    {
        if (filterContext.ActionDescriptor is ControllerActionDescriptor controllerAction
            && controllerAction.MethodInfo.GetCustomAttributes(typeof(OverrideAuthorizeAttribute), true).Any())
        {
            return;
        }
        m_authorizeFilter.OnAuthorizationAsync(filterContext).Wait();
    }
}

public class OverrideAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext filterContext) { }
}

回答by AliR?za Ad?yah?i

If use it on controller then, all methods of this controller will effected.

如果在控制器上使用它,则该控制器的所有方法都将生效。

[Authorize]
public class SomeController(){

    // all actions are effected
    public ActionResult Action1
    public ActionResult Action2

If you want to prevent for one of these actions, you can use something like this:

如果你想阻止这些操作之一,你可以使用这样的东西:

[Authorize]
public class SomeController(){

    // all actions are effected
    public ActionResult Action1
    public ActionResult Action2

    [AllowAnonymous]
    public ActionResult Action3 // only this method is not effected...