mvc的filter

简介: 如果想要记录ajax的请求和输出信息、内部发生异常记录日志、需要登录认证、需要权限判断;那mvc的各种filter可以帮助你实现你想要的。Mvc框架支持5种不同类型的过滤器;我会按照执行顺序进行简单的demo,再简单的代码分享,万一对一个人有益,也是值的。

如果想要记录ajax的请求和输出信息、内部发生异常记录日志、需要登录认证、需要权限判断;那mvc的各种filter可以帮助你实现你想要的。Mvc框架支持5种不同类型的过滤器;我会按照执行顺序进行简单的demo,再简单的代码分享,万一对一个人有益,也是值的。

1.通过实现IAuthenticationFilter来进行登录认证,如果认证通过继续后续的权限授权等操作;如果认证没有通过跳转登录页面;代码如下:

public class MvcAuthenticationFilter : FilterAttribute, IAuthenticationFilter
    {
        /// <summary>
        /// 是否需要认证 
        /// </summary>
        public bool IsNeedAuthentication { get; set; }

        /// <summary>
        /// 对请求进行身份验证
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnAuthentication(AuthenticationContext filterContext)
        {
            bool flag = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
            if (flag)
            {
                return;
            }
            if (IsNeedAuthentication)
            {
                IPrincipal user;
                if (this.IsAuthenticated(filterContext, out user))
                {
                    filterContext.Principal = user;
                }
                else
                {
                    this.UnauthenticatedRequest(filterContext);
                }
            }
        }

        protected bool IsAuthenticated(AuthenticationContext filterContext, out IPrincipal user)
        {
            user = filterContext.HttpContext.User;
            var cc = filterContext.Controller.ControllerContext.Controller as BaseController;
            if (cc != null && cc.CurrentAdminInfo != null)
            {
                IIdentity identity = user.Identity;
                user = new GenericPrincipal(identity, new[] { "root", "noroot" }); //这里根据实际情况获取用户的角色
                return true;
            }
            return false;
        }

        protected void UnauthenticatedRequest(AuthenticationContext filterContext)
        {
            string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;
            string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl);
            string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
            filterContext.HttpContext.Response.Redirect(loginUrl, true);
        }
        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) { }
    }

2.每个管理后台都少不了权限判断的需求;你可以使用[Authorize(Roles = "r1,r2")] 默认实现进行硬编码,对于用户的权限和角色经常变动的话,或者你需要灵活的处理就需要自定义Authorize,咱们先看下Authorize源代码实现你就会明白


他的实现原理,先判断是否有匿名访问标签,然后利用AuthorizeCore 授权检查,如果未授权利用HandleUnauthorizedRequest 放回401,跳转到登录页面;很明显授权不通过跳转登录页面不是太合适;另一种实现方式 自定义Authorize 代码如下:

        public new string[] Roles { get; set; }
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            //由原来指定的roles 替换成动态读取的。
            //跟登录用户的roles进行比较。
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }
            if (!httpContext.User.Identity.IsAuthenticated)
            {
                return false;
            }
            if (Roles == null)
            {
                return true;
            }
            if (Roles.Length == 0)
            {
                return true;
            }
            if (Roles.Any(new Func<string, bool>(httpContext.User.IsInRole)))
            {
                return true;
            }
            httpContext.Response.StatusCode = 403;
            return false;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }

        public override void OnAuthorization(AuthorizationContext filterContext)
        {

            bool flag = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
            if (flag)
            {
                return;
            }
            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = filterContext.ActionDescriptor.ActionName;
            string roles = string.Join(",", GetRoles(actionName, controllerName));
            if (!string.IsNullOrWhiteSpace(roles))
            {
                this.Roles = roles.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            }

            base.OnAuthorization(filterContext);
            if (filterContext.HttpContext.Response.StatusCode == 403)
            {
                //跳转未授权页面
                filterContext.Result = new RedirectResult("/Other/Noright");
            }
        }

3.动作过滤器记录一些ajax的输入输出数据,方便排查问题;代码有注释也比较简单直接贴代码了

  public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                var httpContext = filterContext.HttpContext;
                //输入参数
                var req = new JavaScriptSerializer().Serialize(HttpContext.Current.Request.Form.AllKeys.ToDictionary(k => k, k => HttpContext.Current.Request.Form[k]));
                var code = httpContext.Request.GetHashCode();
                var controllerName = filterContext.RouteData.Values["controller"] as string;
                var actionName = filterContext.RouteData.Values["action"] as string;
                var postUrl = controllerName + "/" + actionName;
                LogHelper.WriteDebug(
                    string.Format("RequestUrl:{0};HashCode:{1}</br>RequestParam{2}",
                   postUrl, code,
                    req));
            }
        }

   
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                //输出参数
                var jsonR = filterContext.Result as JsonResult;
                var res = new JavaScriptSerializer().Serialize(jsonR);
                LogHelper.WriteDebug(string.Format("OnActionExecuted---返回值:{0}", res));
            }

        }

4.最后是发生异常的处理,mvc默认实现HandleErrorAttribute,但是也不够灵活,查看源代码


 我们定义之后的代码

    public override void OnException(ExceptionContext filterContext)
        {
            string errCode = "";
            string errMsg = "";
            //自定义错误
            if (filterContext.Exception is ClException)
            {
            }
            else
            {
                errMsg = "未知错误";
                LogHelper.WriteError(filterContext.Exception.Message);
            }
            //如果是ajax请求
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                var result = new ExceptionResponse
                {
                    ErrMsg = errMsg,
                };
                filterContext.Result = new JsonResult()
                {
                    Data = result
                };
            }//500服务器内部错误
            else
            {
                filterContext.Result = new ViewResult() { ViewName = "/Views/Other/Seerro.cshtml" };
            }

            filterContext.ExceptionHandled = true;//阻止golbal里的错误执行
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 500;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;//禁用 IIS 自定义错误
        }

 看下弹出的错误效果

 

目录
相关文章
|
开发框架 缓存 JSON
ASP.NET Core MVC 从入门到精通之Filter
ASP.NET Core MVC 从入门到精通之Filter
175 0
|
XML 前端开发 Java
【Spring MVC 系列】Spring MVC 中 Filter 配置的 6 种方式,看看你了解哪些
Filter 简介 过滤器 Filter 在 Servlet 2.3 版本中被首次提出,唯一的作用就是过滤,它不仅可以过滤请求,还可以过滤响应,当请求到达 Servlet 容器,会先经过 Filter ,然后再交给 Servlet,之后 Filter 还可以对 Servlet 的响应进一步处理。并且多个 Filter 还能形成一个链。使用图示表达如下。
1082 0
【Spring MVC 系列】Spring MVC 中 Filter 配置的 6 种方式,看看你了解哪些
|
前端开发
java202304java学习笔记第六十四天-mvc的请求-ssm-interceptor个filter区别
java202304java学习笔记第六十四天-mvc的请求-ssm-interceptor个filter区别
50 0
|
前端开发
.Net Mvc中Filter过滤器需要注意的坑
<p>  啥也不说,先上代码:</p> <p>  public class ValidateAttribute : ActionFilterAttribute</p> <p>  {</p> <p>  private string _Name=null;</p> <p>  //Action执行前的过滤器</p> <p>  public override void OnActionExecuting(ActionExecutingContext filterContext)</p>
127 0
|
前端开发 Java Spring
spring mvc DispatcherServlet详解之interceptor和filter的区别
首先我们看一下spring mvc Interceptor的功能及实现: http://wenku.baidu.com/link?url=Mw3GaUhCRMhUFjU8iIDhObQpDcbmmRy_IPeumazg0ppnbmwqFUtLp9kSpuPPpeysf6EnHBLYFeWrbjqMq8BlWKQz_7MSDhGQTVl32fpxCMm SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理,其他的作用比如通过它来进行权限验证,或者是来判断用户是否登陆,日志记录,或者限制时间点访问。
1855 0