如何让MVC的AllowAnonymous覆盖自定义AuthorizeAttribute?
嘿,我明白你为啥头疼了——ASP.NET MVC里控制器和Action上的AuthorizeAttribute(包括自定义的子类)是都会执行的,不是你以为的“Action级覆盖控制器级”。这就是为啥你在Login方法上加了AllowAnonymous=true,控制器上的认证逻辑还是会先触发的原因。
不用急着把Login移去新控制器,咱们改改自定义属性的逻辑就能搞定。核心思路是:让你的AuthorizePublic在执行认证前,先检查当前Action是不是允许匿名访问——不管是用你自定义的参数,还是系统自带的[AllowAnonymous]特性。
具体改法
方法1:重写OnAuthorization,优先判断匿名权限
OnAuthorization是认证流程的入口,在这里能拿到当前请求的Action上下文,正好用来做判断:
public class AuthorizePublic : AuthorizeAttribute { public AuthSites Sites { get; set; } public bool AllowAnonymous { get; set; } public override void OnAuthorization(AuthorizationContext filterContext) { // 两种情况都算允许匿名: // 1. Action/控制器标了系统自带的[AllowAnonymous] var hasSystemAllowAnonymous = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true); // 2. 当前属性实例的AllowAnonymous设为true if (hasSystemAllowAnonymous || this.AllowAnonymous) { // 直接跳过认证,不用走后面的逻辑了 return; } // 没满足匿名条件,再执行原有的认证逻辑 base.OnAuthorization(filterContext); } protected override bool AuthorizeCore(HttpContextBase httpContext) { // 这里保留你原来的站点权限检查逻辑就行 // 举个例子: if (!httpContext.User.Identity.IsAuthenticated) { return false; } // 检查当前用户是否属于指定站点... return true; } }
方法2:直接用系统[AllowAnonymous](更简洁)
如果你不想维护自定义的AllowAnonymous参数,也可以直接在Action上贴系统自带的[AllowAnonymous],只要在自定义属性里加个检查就行:
// 控制器代码不用改,Action改成这样: [AuthorizePublic(Sites = AuthSites.Corporate)] public class CorporateController : SecuredController { [AllowAnonymous] // 用系统自带的特性 public ActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; return View(); } } // 自定义属性简化成这样: public class AuthorizePublic : AuthorizeAttribute { public AuthSites Sites { get; set; } public override void OnAuthorization(AuthorizationContext filterContext) { // 检查是否有系统的AllowAnonymous标记 var hasAllowAnonymous = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true); if (hasAllowAnonymous) { return; } base.OnAuthorization(filterContext); } protected override bool AuthorizeCore(HttpContextBase httpContext) { // 你的原有认证逻辑 } }
为啥之前的方法没生效?
- 用系统
[AllowAnonymous]无效:默认的AuthorizeAttribute会自动识别这个特性,但你的自定义子类没重写相关逻辑,所以不会跳过认证。 - 自定义
AllowAnonymous参数无效:控制器级的AuthorizePublic先执行,它的AllowAnonymous是默认的false,所以会触发认证;Action级的属性只是额外跑一遍,没法覆盖前面的结果。 - 新建覆盖属性无效:还是因为控制器和Action的属性都会执行,除非新属性能主动跳过控制器级的逻辑,但默认机制做不到。
这样改完,你的Login Action就能正常匿名访问,不用动控制器结构啦。
内容的提问来源于stack exchange,提问作者Savage
相关产品推荐
相关产品推荐

