Asp.net MVC4:对控制器和操作均进行授权


Answers:


161

你问:

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

简单回答:两者。效果是将这AND两个限制放在一起。我将在下面解释原因...

细节

因此,有几个原因可能会引起您的疑问。

  1. 您想知道与方法相比如何对Action施加附加约束。例如
    • 在控制器级别,以“用户”角色强制用户
    • 在操作级别,另外以“ admin”角色强制用户
  2. 您想要在操作级别替换控制器约束
  3. 您要在操作级别删除控制器约束,并使该方法可用于匿名用户

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

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

情况3。我不需要讨论(使用[AllowAnonymous]),因为它已经遍及整个SO整个Web。只需说一句:如果[AllowAnonymous]在某个动作上指定,则即使该控制器上有动作,该动作也将被公开[Authorize]

您还可以使用全局过滤器使整个网站获得授权,并使用AllowAnonymous您要公开的少数动作或控制器。

[Authorize] 是加性的(案例1)

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

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

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

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

  • 用户名:Bob,角色:用户,无法访问AdminUsersIndex,但可以访问AllUsersIndex
  • 用户名:Jane,角色:管理员,无法访问AdminUsersIndexAllUsersIndex
  • 用户名:Tim,角色:用户和管理员,可以访问AdminUsersIndexAllUsersIndex

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

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

覆盖[Authorize](案例2)

情况2比较棘手。从上面回想起,[Authorize]属性是按先检查全局的顺序,然后依次是控制器,操作。第一个检测到用户不符合授权资格的人赢得了胜利,其他人则没有被召集。

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

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);
    }
}

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

[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();
    }
}

在上面的示例SuperusersIndex中,即使没有“用户”角色的帐户也可以使用该帐户。


我的没有区别。有一个属性范围。授权应移至第一个水坝。这与比较逻辑相同,例如if(condition1&&condition2) 如果第一个条件为假,则编译器不看第二个条件并跳过if块。
2013年

感谢您提供非常详细的信息,这是我问这个问题时想学的内容。谢谢!
坦率

“用户”角色可以访问SuperusersIndex操作方法吗?
2014年

1
号的OverrideAuthorize完全替代通过定义的默认权限DefaultAuthorize凭借的if (action.IsDefined(typeof(OverrideAuthorizeAttribute), true)) return;DefaultAuthorizeAttribute.OnAuthorization
安迪布朗

5
在MVC5中,情况2可以简单地通过将[OverrideAuthorization]属性添加到操作中来完成,如本答案所述
Bpainter

45

我想向覆盖[授权]添加一些内容(案例2)

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();
    }
}

但这不适用于Custom AuthorizeAttribute对吗?
David Liang

2
需要MVC 5
查Kasabula

它帮助了我。但是请在回答中补充一下它是MVC5,以防人们错过它。
Craig Brett

2

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

[Authorize]
public class SomeController(){

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

如果要防止这些操作之一,则可以使用以下方法:

[Authorize]
public class SomeController(){

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

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

1
OP询问如果[Authorize]同时放置控制器和动作“哪一个会生效?两者都发生?会发生什么,您还没有回答。
安迪·布朗

@Andy Brown,所以,如果他在控制器上定义它,则无需在此控制器的任何操作上编写它。不需要在动作上使用它。您可以从我的答案中了解。我的意思是也无需解释。
AliRızaAdıyahşi

2
我认为,如果您清楚地阅读了答案,那么他已经回答了。由于他说所有方法都会受到影响,这意味着您也可以将其应用于任何操作都无关紧要。
Nick N.

1
@NickN。我的观点是,它可以不管。Authorize属性链接在一起。如果第一个允许用户,第二个仍然可以阻止用户。另外,问题是大约两个Authorize属性(一个控制器上,一个在动作),不Authorize然后AllowAnonymous。我添加了另一个答案来说明我的观点。
安迪·布朗

@AndyBrown我同意你的要求,现在我已经看到了你的答案。
Nick N.

2

我对ASP.NET Core 2.1的第二个答案作了改编。

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

我所做的是,我创建了一个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) { }
}

这是行不通的。只要看一下OnAuthorizationAsync-的实现,GetEffectivePolicyAsync总会返回null,因为GetEffectivePolicyAsync仅适用于实际应用于我们的授权过滤器未实际应用到控制器/动作的过滤器。我们仅将其保留在m_authorizeFilter...
Jan Palas 19'Jul
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.