zoukankan      html  css  js  c++  java
  • MVC之自定义过滤器(ActionFilterAttribute)

    一、自定义Filter

    自定义Filter需要继承ActionFilterAttribute抽象类,重写其中需要的方法,来看下ActionFilterAttribute类的方法签名。
        //表示所有操作-筛选器特性的基类
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
        public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
        {
            protected ActionFilterAttribute();      
            //在Action执行之前由 MVC 框架调用。
            public virtual void OnActionExecuting(ActionExecutingContext filterContext);
            //在Action执行之后由 MVC 框架调用。
            public virtual void OnActionExecuted(ActionExecutedContext filterContext);
            //在执行Result之前由 MVC 框架调用。
            public virtual void OnResultExecuting(ResultExecutingContext filterContext);
            //在执行Result后由 MVC 框架调用。
            public virtual void OnResultExecuted(ResultExecutedContext filterContext);      
        }

    过滤器代码

        //自定义过滤器
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
        public class LoginFilterAttribute : ActionFilterAttribute
        {
            ILogger log = LoggerFactory.GetChannelLog(typeof(LogInAuthorizeAttribute));
    
            /// <summary>
            /// 默认登录页面
            /// </summary>
            private static readonly string logUrl = ConfigFactory.WebEnvConfig.Items["LoginToGMS"];
    
            //通过配置cookie名称
            private static readonly  string cookieName = ConfigFactory.WebEnvConfig.Items["CookieName"];
            
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                try
                {
                    log.Debug("自定义Cookie名称,CookieName:" + cookieName);
    
                    var cookie = filterContext.HttpContext.Request.Cookies[cookieName];
    
                    if (cookie == null)
                    {
                         RedirectUrl(filterContext, logUrl);
                    }
                    log.Debug("cookieName:" + cookieName + "cookieValue:" + cookie.Value);
                    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
                    if (ticket == null || string.IsNullOrEmpty(ticket.UserData)) {
                        log.Debug("解密失败! tick  is null or ticket UserData is null :");
                        RedirectUrl(filterContext, logUrl);
                    }
                    log.Debug("解密成功!tick:" + ticket.Name);
                    LoginUser userData = JsonConvert.DeserializeObject<LoginUser>(ticket.UserData);
                    HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new System.Web.Security.FormsIdentity(ticket),new string[0]);
                    log.Debug("!HttpContext.Current.Request.IsAuthenticated:" + HttpContext.Current.Request.IsAuthenticated);
                    log.Debug("获取成功!  Name:" + userData.User_Nm);
                }
                catch (Exception ex)
                {
                    log.Error("解密cookie异常:"+ex.Message);
                    log.Error(ex);
                    filterContext.HttpContext.Response.Cookies.Clear();
                    RedirectUrl(filterContext, logUrl);
                }
                base.OnActionExecuting(filterContext);         
            }
            
            /// <summary>
            /// 跳转报错解决办法
            /// </summary>
            /// <param name="url"></param>
            public void RedirectUrl(ActionExecutingContext filterContext, string url)
            {
                filterContext.HttpContext.Response.Clear();//这里是关键,清除在返回前已经设置好的标头信息,这样后面的跳转才不会报错
                filterContext.HttpContext.Response.BufferOutput = true;//设置输出缓冲
                if (!filterContext.HttpContext.Response.IsRequestBeingRedirected)//在跳转之前做判断,防止重复
                {
                    //filterContext.HttpContext.Response.Redirect(url, true);//在Filter中用Response.Redirect,虽然URL是跳转了,但是之后的Filter和Action还是会执行,不仅浪费资源,还会产生一些不必要的错误
                    filterContext.Result = new RedirectResult(url);
                }
            }

    注意过滤器也可以放在整个Controller类的顶部,表示该Controller下的所有Action都执行该项检查。这样一来,控制器里的代码非常漂亮,再也不用所有的Action里都充斥着判断登录的代码了。

    顺便说下登录成功后如何将用户信息写入Cookie中

       LoginUser loginUser = new LoginUser();                  
       loginUser.UserId = userfile.User_Id;
       loginUser.User_Cd = userfile.User_Cd;
       loginUser.User_Nm = userfile.User_Nm;                   
    
       FormsAuthentication.SetAuthCookie(UserName, false);
       FormsAuthenticationTicket Ticket = new FormsAuthenticationTicket(1, UserName, DateTime.Now, DateTime.Now.AddTicks(FormsAuthentication.Timeout.Ticks), false, JsonConvert.SerializeObject(loginUser));
       string HashTicket = FormsAuthentication.Encrypt(Ticket);
       HttpCookie UserCookie = new HttpCookie(FormsAuthentication.FormsCookieName, HashTicket);
                          
       UserCookie.Domain = FormsAuthentication.CookieDomain;
       UserCookie.Path = "/"; 
    View Code

    同时在Web.config中配置如下:

    <authentication mode="Forms">
        <forms path="/" loginUrl="/login" defaultUrl="/" protection="All" name=".newpower" domain="" timeout="60" slidingExpiration="true" />
    </authentication>

    二、带参数的自定义Filter

    首先,还是按照之前添加自定义过滤器的方法,添加一个自定义过滤器,只是里面多了一个属性,代码如下:

    public class FilterAttribute : ActionFilterAttribute
        {
            public string Message { get; set; }
     
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                base.OnActionExecuting(filterContext);
                filterContext.HttpContext.Response.Write("Action执行之前" + Message + "<br />");
            }
     
            public override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                base.OnActionExecuted(filterContext);
                filterContext.HttpContext.Response.Write("Action执行之后" + Message + "<br />");
            }
     
            public override void OnResultExecuting(ResultExecutingContext filterContext)
            {
                base.OnResultExecuting(filterContext);
                filterContext.HttpContext.Response.Write("返回Result之前" + Message + "<br />");
            }
     
            public override void OnResultExecuted(ResultExecutedContext filterContext)
            {
                base.OnResultExecuted(filterContext);
                filterContext.HttpContext.Response.Write("返回Result之后" + Message + "<br />");
            }
        }
    View Code

    然后在调用过滤器的时候,添加上该参数,Controller代码如下:

    [Filter(Message="刘备")]  //参数给上
     public ActionResult Index()
    {
          return View();
    }
    View Code

    如果标签打到Controller上的话,FilterAttribute将作用到Controller下的所有的Action。

    默认情况下Action上打了某个自定义标签后,虽然在Controller上也打上了此标签,但它只有Action上的标签起作用了。
    补充:如果Action没有打上该标签,那么Controller上的标签便会被执行。

    如果想让Action上的标签执行一次,然后Controller上的标签也执行一次,那么应该如何操作呢?

    我们只需在FilterAttribute类的定义上打上标记[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]即可【下面类的最上面红色字体部分】,也就是让其成为可以多次执行的Action。代码如下:

    [AttributeUsage(AttributeTargets.All,AllowMultiple = true)]
    public class FilterAttribute : ActionFilterAttribute
    {
            public string Message { get; set; }
            ......
    View Code

    三、全局过滤器 

    创建一个全局action过滤器  (在appstart  的 filterconfig中注册   filters.Add(new LoginFilterAttribute());)

    这样就每个Action都会执行此过滤器,而不必每个Controller顶部都加上标签。    

    public class FilterConfig
    {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
                //注册全局过滤器
                filters.Add(new LoginFilterAttribute() { Message = "全局" });
            }
    }
    View Code

               

  • 相关阅读:
    Java入门系列之集合Hashtable源码分析(十一)
    哈希算法原理【Java实现】(十)
    Java入门系列之集合LinkedList源码分析(九)
    双链表算法原理【Java实现】(八)
    Java入门系列之集合ArrayList源码分析(七)
    动态数组原理【Java实现】(六)
    Java入门系列之类继承、抽象类、接口(五)
    Java入门系列之包装类(四)
    Java入门系列之StringBuilder、StringBuffer(三)
    Java入门系列之字符串特性(二)
  • 原文地址:https://www.cnblogs.com/li150dan/p/9958080.html
Copyright © 2011-2022 走看看