如果我在控制器和操作上都有 Authorize 属性,哪个会生效?还是两者都会生效?
4 回答
您问:
如果我在控制器和动作上都有 Authorize 属性,哪个会生效?两个都?
简单地回答这个问题:两者兼而有之。效果是把AND
两个限制放在一起。我将在下面解释为什么...
细节
所以,你可能会问这个问题有几个原因。
- 与方法相比,您想知道如何对 Action 实施额外的约束。例如
- 在控制器级别,强制用户扮演“用户”角色
- 在操作级别,另外强制用户具有“管理员”角色
- 您想在操作级别替换控制器约束
- 您想在操作级别删除控制器约束并使该方法对匿名用户可用
您没有指定您的 MVC 版本,因此我将假定为今天的最新版本(MVC 4.5)。但是,即使您使用的是 MVC 3,答案也不会有太大变化。
[Anonymous]
覆盖控制器[Authorize]
(案例 3)
案例3。我不需要覆盖(使用[AllowAnonymous]
),因为它已经在整个SO和整个网络上得到了回答。可以这么说:如果你指定[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,角色:admin,无法访问
AdminUsersIndex
或AllUsersIndex
- 用户名:Tim,角色:用户和管理员,可以访问
AdminUsersIndex
和AllUsersIndex
这说明该[Authorize]
属性是可加的。Users
属性的属性也是如此,可以将其组合Roles
以使其更具限制性。
这种行为是由于控制器和操作属性的工作方式造成的。这些属性被链接在一起并应用于订单控制器然后是操作。如果第一个拒绝授权,则控制返回并且不调用操作的属性。如果第一个通过了授权,那么第二个也将被检查。Order
您可以通过指定(例如[Authorize(Roles = "user", Order = 2)]
)来覆盖此顺序。
覆盖[Authorize]
(案例 2)
案例 2 更棘手。回想一下,[Authorize]
属性的检查顺序是(全局然后)控制器然后动作。第一个检测到用户没有资格被授权的获胜,其他人不会被调用。
解决此问题的一种方法是定义两个新属性,如下所示。The[OverrideAuthorize]
除了遵从[Authorize]
; 它的唯一目的是定义一个我们可以检查的类型。允许我们检查请求中调用的[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
中,具有“超级用户”角色的帐户可以使用,即使它没有“用户”角色。
我想在 Overriding [Authorize] 中添加一些内容(案例 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();
}
}
如果在控制器上使用它,则该控制器的所有方法都将生效。
[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...
我为 ASP.NET Core 2.1改编了这个答案的第二种情况。
与 ASP.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) { }
}