[英]Get MVC AllowAnonymous to override custom authorize attribute
I have created a custom authorize attribute, but I need some actions to allow anonymous access. 我已经创建了一个自定义授权属性,但是我需要一些操作来允许匿名访问。 I've tried three different approaches without success: use
AllowAnonymous
, update the existing attribute with additional parameters, and create a new overriding attribute. 我尝试了三种不同的方法,但
AllowAnonymous
成功:使用AllowAnonymous
,使用其他参数更新现有属性以及创建新的覆盖属性。 Basically it seems that the controller-level attribute always gets called before the action-level attribute. 基本上,似乎总是在操作级属性之前调用控制器级属性。
Here's the controller: 这是控制器:
[AuthorizePublic(Sites = AuthSites.Corporate)]
public class CorporateController : SecuredController
{
[AuthorizePublic(Sites = AuthSites.Corporate, AllowAnonymous = true)]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
}
And the attribute: 和属性:
public class AuthorizePublic : AuthorizeAttribute
{
public AuthSites Sites { get; set; }
public bool AllowAnonymous { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// Logic
}
}
As a last resort I can move the login actions onto their own controller, but before I do that, am I missing something to get one of these approaches to work? 作为最后的选择,我可以将登录操作移至其自己的控制器上,但是在此之前,我是否缺少使这些方法之一起作用的东西? I'm a bit surprised that action-level attributes aren't overriding controller-level attributes.
我对动作级属性没有覆盖控制器级属性感到惊讶。
It is the implementation of the OnAuthorization
method of AuthorizeAttribute
that scans for AllowAnonymousAttribute
. AuthorizeAttribute
的OnAuthorization
方法的实现将扫描AllowAnonymousAttribute
。 So, you must either not override this method or re-implement this check if you want that part to work. 因此,如果您希望该部分正常工作,则不能覆盖此方法或重新实施此检查。 Since you have only provided a cut-down implementation of
AuthorizeAttribute
, it cannot be assumed that you are not overriding this method (and thus overriding the logic that makes the check). 由于您仅提供了
AuthorizeAttribute
的简化实现,因此不能假定您没有覆盖此方法(因此也没有覆盖进行检查的逻辑)。
Also, your example controller doesn't actually show usage of the AllowAnonymousAttribute
. 同样,您的示例控制器实际上并未显示
AllowAnonymousAttribute
用法 。 Instead, it sets a property named AllowAnonymous
. 而是设置一个名为
AllowAnonymous
的属性。 If you expect anonymous users to reach that action method, you should decorate it with the attribute that MVC is actually scanning for. 如果希望匿名用户使用该操作方法,则应使用MVC实际扫描的属性来装饰它。
[AuthorizePublic(Sites = AuthSites.Corporate)]
public class CorporateController : SecuredController
{
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
}
Alternatively, if you need to customize the AllowAnonymous
behavior in some way, you can keep using the property you have, but you have to implement the Reflection code yourself to scan for AuthorizePublic
and check the AllowAnonymous
property. 另外,如果您需要以某种方式自定义
AllowAnonymous
行为,则可以继续使用拥有的属性,但是必须自己实现反射代码以扫描AuthorizePublic
并检查AllowAnonymous
属性。
public class AuthorizePublic : AuthorizeAttribute
{
public AuthSites Sites { get; set; }
public bool AllowAnonymous { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var actionDescriptor = httpContext.Items["ActionDescriptor"] as ActionDescriptor;
if (actionDescriptor != null)
{
AuthorizePublic attribute = GetAuthorizePublicAttribute(actionDescriptor);
if (attribute.AllowAnonymous)
return true;
var sites = attribute.Sites;
// Logic
}
return true;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
// Pass the current action descriptor to the AuthorizeCore
// method on the same thread by using HttpContext.Items
filterContext.HttpContext.Items["ActionDescriptor"] = filterContext.ActionDescriptor;
base.OnAuthorization(filterContext);
}
// Gets the Attribute instance of this class from an action method or contoroller.
// An action method will override a controller.
private AuthorizePublic GetAuthorizePublicAttribute(ActionDescriptor actionDescriptor)
{
AuthorizePublic result = null;
// Check if the attribute exists on the action method
result = (AuthorizePublic)actionDescriptor
.GetCustomAttributes(attributeType: typeof(AuthorizePublic), inherit: true)
.SingleOrDefault();
if (result != null)
{
return result;
}
// Check if the attribute exists on the controller
result = (AuthorizePublic)actionDescriptor
.ControllerDescriptor
.GetCustomAttributes(attributeType: typeof(AuthorizePublic), inherit: true)
.SingleOrDefault();
return result;
}
}
AuthorizeAttribute
implements both Attribute
and IAuthorizationFilter
. AuthorizeAttribute
实现Attribute
和IAuthorizationFilter
。 With that in mind, the IAuthorizationFilter
part of AuthorizeAttribute
is a different runtime instance of the class than the Attribute
part. 考虑到这一点,
AuthorizeAttribute
的IAuthorizationFilter
部分与Attribute
部分是类的不同运行时实例 。 So the former must use Reflection to read the property of the latter in order for it to work. 因此,前者必须使用反射来读取后者的属性,以使其起作用。 You can't just read the
AllowAnonymous
property from the current instance and expect it to work, because you are setting the value in the attribute and the code is executing in the filter. 您不能只是从当前实例中读取
AllowAnonymous
属性并期望它起作用,因为您正在属性中设置值,并且代码正在过滤器中执行。
MVC and Web API are completely separate frameworks with their own separate configuration even though they can co-exist in the same project.
MVC和Web API是完全独立的框架,具有各自独立的配置,即使它们可以共存于同一项目中。 MVC will completely ignore any controllers or attributes defined in Web API and vise versa.
MVC将完全忽略Web API中定义的任何控制器或属性,反之亦然。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.