Net MVC4: 对控制器和操作进行授权

如果我在控制器和操作上都有 Authorize 属性,那么哪一个会起作用?或者两者都会生效?

79655 次浏览

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

[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...

你问:

如果我在控制器和操作上都有 Authorize 属性,那么哪一个会起作用? 两者?

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

细节

所以,你问这个问题有几个原因。

  1. 您想知道与方法相比,如何对 Action 实施附加约束。
    • 在控制器级别,强制用户扮演“用户”角色
    • 在操作级别,还要在角色“ admin”中强制用户
  2. 您希望在操作级别替换控制器约束
  3. 您希望在操作级别移除控制器约束,并使该方法对匿名用户可用

您没有指定您的 MVC 版本,所以我将假设最新的版本(MVC 4.5)。然而,即使你使用的是 MVC 3,这个问题的答案也不会有太大的改变。

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

案例3。我不需要覆盖(使用 [AllowAnonymous]) ,因为它已经回答了 所以网上到处都是。简单地说: 如果您在一个操作上指定 [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)

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

解决这个问题的一种方法是像下面这样定义两个新属性。除了遵从 [Authorize]之外,[OverrideAuthorize]什么也不做; 它的唯一用途是定义一个我们可以检查的类型。[DefaultAuthorize]允许我们检查请求中调用的 Action 是否用 [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);
}
}

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

[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可用于具有“超级用户”角色的帐户,即使它不具有“用户”角色。

我想添加一些内容到重写[授权](情况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();
}
}

我为 ASP.NET Core 2.1改编了 这个答案是第二种情况

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

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