在webform中,验证的流程大致如下图:

在AOP中:

在Filter中:

AuthorizeAttribute权限验证

登录后有权限控制,有的页面是需要用户登录才能访问的,需要在访问页面增加一个验证,也不能每个action都一遍。

1、写一个CustomAuthorAttribute,继承自AuthorizeAttribute,重写OnAuthorization方法,在里面把逻辑写成自己的。

2、有方法注册和控制器注册。

3、有全局注册,全部控制器全部action都生效。

但是在这个里面,首先要验证登录首页,首页没有邓丽,就跑到登录页面了,但是登录页面也要走特性里面的逻辑,又重定向到邓丽。。。循环了。。。。

这里有一个AlloAnonymous,这个标签就可以解决这个循环的问题,匿名支持,不需要登录就可以,但是单单加特性是没有用的,其实需要验证时支持,甚至可以说自己自定义一个特性也是可以的,这个特性里面是空的,只是为了用来做标记。

特性的使用范围,希望特性通用,在不同的系统,不同的地址登录,==》在特性上面加个传参的构造函数。

 public class CustomAllowAnonymousAttribute : Attribute{}

CustomAuthorAttribute类

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{private Logger logger = new Logger(typeof(CustomAuthorizeAttribute));private string _LoginUrl = null;public CustomAuthorizeAttribute(string loginUrl = "~/Home/Login"){this._LoginUrl = loginUrl;}//public CustomAuthorizeAttribute(ICompanyUserService service)//{//}//不行public override void OnAuthorization(AuthorizationContext filterContext){var httpContext = filterContext.HttpContext;//能拿到httpcontext 就可以为所欲为if (filterContext.ActionDescriptor.IsDefined(typeof(CustomAllowAnonymousAttribute), true)){return;}else if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(CustomAllowAnonymousAttribute), true)){return;}else if (httpContext.Session["CurrentUser"] == null|| !(httpContext.Session["CurrentUser"] is CurrentUser))//为空了,
        {//这里有用户,有地址 其实可以检查权限if (httpContext.Request.IsAjaxRequest())//httpContext.Request.Headers["xxx"].Equals("XMLHttpRequst")
            {filterContext.Result = new NewtonJsonResult(new AjaxResult(){Result = DoResult.OverTime,DebugMessage = "登陆过期",RetValue = ""});}else{httpContext.Session["CurrentUrl"] = httpContext.Request.Url.AbsoluteUri;filterContext.Result = new RedirectResult(this._LoginUrl);//短路器:指定了Result,那么请求就截止了,不会执行action
            }}else{CurrentUser user = (CurrentUser)httpContext.Session["CurrentUser"];//this.logger.Info($"{user.Name}登陆了系统");return;//继续
        }//base.OnAuthorization(filterContext);
    }
}

Filter生效机制

为什么加个标签,继承AuthorizeAttribute,重写OnAuthorization方法就可以了呢?控制器已经实例化,调用ExecuteCore方法,找到方法名字,ControllerActionInvokee.InvokeAction,找到全部的Filter特性,InvokeAuthorize--result不为空,直接InvokeActionResult,为空就正常执行Action。

有一个实例类型,有一个方法名称,希望你反射执行

在找到方法后,执行方法前,可以检测下特性,来自全局的、来自控制器的、来自方法的。价差特性,特性是自己预定义的,按类执行,定个标识,为空就正常,不为空就跳转,正常就继续执行。

Filter原理和AOP面向切面编程

Filter是AOP思想的一种实现,其实就是ControllerActionInvoke这个类中,有个InvokeAction方法,控制器实例化之后,ActionInvoke前后,通过检测预定义Filter并且执行它,达到AOP的目的。

下面是InvokeAction的源码:

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName){if (controllerContext == null){throw new ArgumentNullException("controllerContext");}if (string.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch()){throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");}ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);if (actionDescriptor != null){FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);try{AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor);if (authenticationContext.Result != null){AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result);this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result);}else{AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);if (authorizationContext.Result != null){AuthenticationChallengeContext authenticationChallengeContext2 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authorizationContext.Result);this.InvokeActionResult(controllerContext, authenticationChallengeContext2.Result ?? authorizationContext.Result);}else{if (controllerContext.Controller.ValidateRequest){ControllerActionInvoker.ValidateRequest(controllerContext);}IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);AuthenticationChallengeContext authenticationChallengeContext3 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, actionExecutedContext.Result);this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, authenticationChallengeContext3.Result ?? actionExecutedContext.Result);}}}catch (ThreadAbortException){throw;}catch (Exception exception){ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);if (!exceptionContext.ExceptionHandled){throw;}this.InvokeActionResult(controllerContext, exceptionContext.Result);}return true;}return false;}

View Code

全局异常处理HandleErrorAttribute

关于异常处理的建议:

  1、避免UI层直接看到异常,每个控制器里面try-catch一下?不是很麻烦吗?

  2、这个时候,AOP就登场了,HandleErrorAttribute,自己写一个特性,继承之HandleErrorAttribute,重写OnException,在发生异常之后,会跳转到这个方法。

在这边,一定要

 public class CustomHandleErrorAttribute : HandleErrorAttribute{private Logger logger = new Logger(typeof(CustomHandleErrorAttribute));/// <summary>/// 会在异常发生后,跳转到这个方法/// </summary>/// <param name="filterContext"></param>public override void OnException(ExceptionContext filterContext){var httpContext = filterContext.HttpContext;//"为所欲为"if (!filterContext.ExceptionHandled)//没有被别的HandleErrorAttribute处理
         {this.logger.Error($"在响应 {httpContext.Request.Url.AbsoluteUri} 时出现异常,信息:{filterContext.Exception.Message}");//
             if (httpContext.Request.IsAjaxRequest()){filterContext.Result = new NewtonJsonResult(new AjaxResult(){Result = DoResult.Failed,DebugMessage = filterContext.Exception.Message,RetValue = "",PromptMsg = "发生错误,请联系管理员"});}else{filterContext.Result = new ViewResult()//短路器
                 {ViewName = "~/Views/Shared/Error.cshtml",ViewData = new ViewDataDictionary<string>(filterContext.Exception.Message)};}filterContext.ExceptionHandled = true;//已经被我处理了
         }}}

这个是要重新跳转的地址:

一定要考虑到是不是Ajax请求的

多种异常情况,能不能进入自定义的异常呢?

1、Action异常,没有被Catch

2、Action异常,被Catch

3、Action调用Service异常

4、Action正常视图出现异常了

5、控制器构造出现异常

6、Action名称错误

7、任意地址错误

8、权限Filter异常

答案:

1、可以

2、不可以

3、可以,异常冒泡

4、可以,为什么呢?因为ExecuteResult是包裹在try里面的

5、不可以的,Filter是在构造完成控制之后方法执行之前完成的

6、不可以的,因为请求都没进MVC流程

7、不可以的,因为请求都没进MVC

8、可以的,权限Filter也是在try里面的。

那这些没有被捕获的异常怎么办?还有一个方法

在Global中增加一个事件

 public class MvcApplication : System.Web.HttpApplication{private Logger logger = new Logger(typeof(MvcApplication));protected void Application_Start(){AreaRegistration.RegisterAllAreas();//注册区域FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//注册全局的FilterRouteConfig.RegisterRoutes(RouteTable.Routes);//注册路由BundleConfig.RegisterBundles(BundleTable.Bundles);//合并压缩 ,打包工具 CombresControllerBuilder.Current.SetControllerFactory(new ElevenControllerFactory());this.logger.Info("网站启动了。。。");}/// <summary>/// 全局式的异常处理,可以抓住漏网之鱼/// </summary>/// <param name="sender"></param>/// <param name="e"></param>protected void Application_Error(object sender, EventArgs e){Exception excetion = Server.GetLastError();this.logger.Error($"{base.Context.Request.Url.AbsoluteUri}出现异常");Response.Write("System is Error....");Server.ClearError();//Response.Redirect//base.Context.RewritePath("/Home/Error?msg=")}

HandleErrorAttribute+Application_Error,粒度不一样,能拿到的东西不一样

IActionFilter扩展定制

IActionFilter

1、OnActionExecuting   方法执行前

2、OnActionExecuted方法执行后

3、OnResultExecuting结果执行前

4、OnResultExecuted结果执行后

先执行权限Filter,再执行ActionFilter。

执行的顺序:

  Global OnActionExecuting

  Controller OnActionExecuting

  Action OnActionExecuting

  Action真实执行

  Action OnActionExecuted

  Controller OnActionExecuted

  Global OnActionExecuted

不同位置注册的生效顺序:全局---》控制器-----》Action

好像一个俄罗斯套娃,或者说洋葱模型

在同一个位置注册的生效顺序,同一个位置按照先后顺序生效,还有一个Order的参数,不设置Order默认是1,设置之后按照从小到大执行

ActionFilter能干什么?

日志、参数检测、缓存、重写视图、压缩、防盗链、统计访问、不同的客户端跳转不同的页面、限流.....

浏览器请求时,会声明支持的格式,默认的IIS是没有压缩的,检测了支持的格式,在响应时将数据压缩(IIS服务器完成的),在响应头里面加上Content-Encoding,浏览器查看数据格式,按照浏览器格式解压(无论你是什么东西,都可以压缩解压的),压缩是IIS,解压是浏览器的。

 public class CompressActionFilterAttribute : ActionFilterAttribute{public override void OnActionExecuting(ActionExecutingContext filterContext){//foreach (var item in filterContext.ActionParameters)//{//    //参数检测  敏感词过滤//}  var request = filterContext.HttpContext.Request;var respose = filterContext.HttpContext.Response;string acceptEncoding = request.Headers["Accept-Encoding"];//检测支持格式if (!string.IsNullOrWhiteSpace(acceptEncoding) && acceptEncoding.ToUpper().Contains("GZIP")){respose.AddHeader("Content-Encoding", "gzip");//响应头指定类型respose.Filter = new GZipStream(respose.Filter, CompressionMode.Compress);//压缩类型指定
         }}}public class LimitActionFilterAttribute : ActionFilterAttribute{private int _Max = 0;public LimitActionFilterAttribute(int max = 1000){this._Max = max;}public override void OnActionExecuting(ActionExecutingContext filterContext){string key = $"{filterContext.RouteData.Values["Controller"]}_{filterContext.RouteData.Values["Action"]}";//CacheManager.Add(key,) 存到缓存key 集合 时间  filterContext.Result = new JsonResult(){Data = new { Msg = "超出频率" }};}}

Filter这么厉害,有没有什么局限性????

虽然很丰富,但是只能以Action为单位,Action内部调用别的类库,加操作就做不到!这种就得靠IOC+AOP扩展。

本篇只是介绍了.NET Framework MVC 中的过滤器Filter(权限特性、Action、Result、Exception),其实在.NET Core MVC 增加了ResourceFilter,加了这个特性,资源特性,Action/Result /Exception三个特性没有什么变化。后面记录到到.NET Core MVC时再详细介绍。

转载于:https://www.cnblogs.com/taotaozhuanyong/p/11575590.html

.NET MVC5简介(四)Filter和AuthorizeAttribute权限验证相关推荐

  1. Shiro安全(四):Shiro权限绕过之Shiro-782

    Shiro安全(四):Shiro权限绕过之Shiro-782 0x00 前言 0x01 前置知识 0x02 漏洞环境 0x03 漏洞利用 0x04 漏洞原理 Shiro层面绕过 Spring层面绕过 ...

  2. java springmvc权限校验_详解Spring MVC使用Filter实现登录及权限验证判断

    登录和权限验证判断在后台管理系统中是最常用的功能,这部分代码是比较固定和独立的,为了减少对业务代码入侵性,一般我会考虑使用Filter来实现,下面我就来详细说一下我的实现思路和代码: 前台页面: St ...

  3. Django - Xadmin (四) Filter

    Django - Xadmin (四) Filter Filter 功能描述 与 admin 组件中 Filter 功能类似,在展示页面右侧放置一列标签,通过点击这些标签来筛选出该标签相关的数据. 比 ...

  4. Java的四种包访问权限

    Java的四种包访问权限如下: private default protected public 同一类 √ √ √ √ 同一包 √ √ √ 不同包的子类 √ √ 不同包的非子类 √

  5. 哈工程计算机学院研究生导师,哈尔滨工程大学自动化研究生导师简介四.doc

    哈尔滨工程大学自动化研究生导师简介 四 ? 莫宏伟男,1973年5月生,工学博士,教授,博士生导师 模式识别与智能系统研究所副所长 指导博士生学科:模式识别与智能系统 指导硕士生学科:第一专业:模式识 ...

  6. ASP.net MVC5 简介

    ASP.net MVC5 简介 MVC是什么 MVC是一种设计模式. 也就是Model-View-Controller 模型-视图-控制器. Model的功能 Model试数据模型,用来封装与程序相关 ...

  7. Linux 基础命令(四)—— 文件的权限和访问控制列表(ACL)

    Linux 基础命令(四)-- 文件的权限和访问控制列表(ACL)  Published On July 24, 2017 前言 查看全文 http://www.taodudu.cc/news/sho ...

  8. 2_MVC+EF+Autofac(dbfirst)轻型项目框架_用户权限验证

    前言 接上面两篇 0_MVC+EF+Autofac(dbfirst)轻型项目框架_基本框架 与 1_MVC+EF+Autofac(dbfirst)轻型项目框架_core层(以登陆为例) .在第一篇中介 ...

  9. [Abp 源码分析]权限验证

    点击上方蓝字关注我们 0.简介 Abp 本身集成了一套权限验证体系,通过 ASP.NET Core 的过滤器与 Castle 的拦截器进行拦截请求,并进行权限验证.在 Abp 框架内部,权限分为两块, ...

最新文章

  1. mysql多语句查询结果_MySQL查询从多个选择语句获取结果?
  2. python学精通要多久-精通python要多久
  3. 软件界面中英文对照_再也不用翻译软件了,弱电行业术语大全及中英文对照表来了~...
  4. POJ:3579-Median(二分+尺取寻找中位数)
  5. 计算机电子琴弹奏怎么打开,怎么打开电脑键盘电子琴软件
  6. leetcode 234. 回文链表(快慢指针+链表倒置)
  7. java学习(178):终篇?静态代理?动态代理?
  8. ssg国际数字货币商城源码货币商城+数字货币+双端APP
  9. 七夕赶上服务器架构升级,女朋友的约会怎么办
  10. 使用 IntraWeb (12) - 基本控件之 TIWGradButton、TIWImageButton
  11. empty string什么错误_go语言的interface为什么好用?
  12. 微软更新补丁下载地址
  13. Android 计算视频的fps
  14. 5g网络模式是以什么划分的_5G组网的8种方式,有什么不同?各方式又怎么进行网络部署...
  15. sonic配置team与实现机制
  16. 数据仓库分层 (ODS、DWD、DWS)
  17. Puppet学习之hiera(8)
  18. python3实现softmax + 函数曲线绘制
  19. 2013年第四届C/C++ A组蓝桥杯省赛真题
  20. 最详细的原版win8系统安装指南,重装原版系统不再求人!

热门文章

  1. 硬核干货长文!Hbase来了解一下不?
  2. java if后面要加大括号
  3. Unity3d学习笔记-无限循环滚动背景(完整的商店广告牌组件)
  4. 【FAQ】应用内支付服务无法拉起支付页面常见原因分析和解决方法
  5. 一元多项式的乘法与加法运算
  6. Recycler 笔记
  7. POJ - 2564 Edit Step Ladders
  8. 网站安全性评估内容要求
  9. grep命令基本用法
  10. 硬核拆解100W车充应用—拓尔微一站式快充解决方案全程在线