如果我在控制器和操作上都具有Authorize属性,哪个将生效?还是会同时生效?
Answers:
你问:
如果我在控制器和动作上都具有Authorize属性,哪个将生效?都?
简单回答:两者。效果是将这AND
两个限制放在一起。我将在下面解释原因...
因此,有几个原因可能会引起您的疑问。
您没有指定您的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
您必须同时具有“用户”和“管理员”角色。例如:
AdminUsersIndex
,但可以访问AllUsersIndex
AdminUsersIndex
或AllUsersIndex
AdminUsersIndex
和AllUsersIndex
这说明该[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块。
SuperusersIndex
操作方法吗?
OverrideAuthorize
完全替代通过定义的默认权限DefaultAuthorize
凭借的if (action.IsDefined(typeof(OverrideAuthorizeAttribute), true)) return;
在DefaultAuthorizeAttribute.OnAuthorization
我想向覆盖[授权]添加一些内容(案例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...
[Authorize]
同时放置控制器和动作“哪一个会生效?两者都发生? ”会发生什么,您还没有回答。
Authorize
属性链接在一起。如果第一个允许用户,第二个仍然可以阻止用户。另外,问题是大约两个Authorize
属性(一个控制器上,一个在动作),不Authorize
然后AllowAnonymous
。我添加了另一个答案来说明我的观点。
我对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
...