MVC5控制器Action特性加载优先级及Authorize执行顺序问题
自定义Permission特性提前执行问题
MVC5 过滤器管道按固定优先级执行:授权过滤器(Authorization Filter)→ 动作过滤器(Action Filter)→ 结果过滤器(Result Filter)→ 异常过滤器(Exception Filter)。同类型过滤器默认按「全局注册→控制器标注→Action标注」的顺序执行,也可通过Order属性手动调整顺序。
未认证状态下Permission特性提前触发,核心原因是自定义Permission特性没有绑定到授权管道的正确阶段:多数开发者实现自定义权限时直接继承ActionFilterAttribute,或实现IAuthorizationFilter时未优先做身份认证状态校验,甚至执行顺序优先级高于内置[Authorize]特性。
修复方式
不要单独实现独立的Permission过滤器,直接让PermissionAttribute继承内置的AuthorizeAttribute,将权限校验逻辑放到重写的AuthorizeCore方法中。内置AuthorizeAttribute会优先完成身份认证状态校验,认证通过后才会进入自定义权限判断逻辑,参考实现:
public class PermissionAttribute : AuthorizeAttribute { public int ModuleId { get; set; } protected override bool AuthorizeCore(HttpContextBase httpContext) { // 先执行基类身份认证校验,未认证直接返回false,不执行后续权限逻辑 if (!base.AuthorizeCore(httpContext)) { return false; } // 此处编写自定义权限校验逻辑,例如判断当前用户是否持有ModuleId对应权限 bool hasPermission = false; // 业务权限判断代码 return hasPermission; } protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { // 区分未认证、无权限两种场景返回对应结果 if (!filterContext.HttpContext.User.Identity.IsAuthenticated) { base.HandleUnauthorizedRequest(filterContext); } else { // 已认证但无权限返回403状态码,或跳转自定义无权限提示页 filterContext.Result = new HttpStatusCodeResult(403); } } }
这种实现天然保证身份认证流程先于权限校验执行,不会出现未认证就触发权限逻辑的问题。
[Authorize]特性重定向到不存在的login.aspx问题
这个是MVC5框架的默认配置问题:web.config中表单认证的默认登录地址为login.aspx,未手动修改配置时,Authorize特性触发未认证跳转时会默认指向该地址,和项目使用MVC框架无关。
修复方式
- 修改根目录
web.config中<system.web>节点下的认证配置,将登录地址改为项目实际的MVC登录路由:<system.web> <!-- 其余配置省略 --> <authentication mode="Forms"> <!-- loginUrl替换为实际的登录页路径,例如下方为Account控制器的Login动作 --> <forms loginUrl="~/Account/Login" timeout="2880" /> </authentication> </system.web> - 如果项目使用ASP.NET Identity,还需要在
App_Start/Startup.Auth.cs(Identity 2.x版本默认路径)中修改Cookie认证配置的登录路径,与web.config配置保持一致:app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), // 与web.config配置保持一致 // 其余Identity配置省略 });
配置完成后,未认证触发跳转时会指向你配置的MVC登录页,不会再请求不存在的login.aspx页面。
内容的提问来源于stack exchange,提问作者Ahad Porkar

