zoukankan      html  css  js  c++  java
  • C# WebApi 过滤器的使用,开发接口必备利器

    在WEB Api中,引入了面向切面编程(AOP)的思想,在某些特定的位置可以插入特定的Filter进行过程拦截处理。引入了这一机制可以更好地践行DRY(Don’t Repeat Yourself)思想,通过Filter能统一地对一些通用逻辑进行处理,如:权限校验、参数加解密、参数校验等方面我们都可以利用这一特性进行统一处理,今天我们来介绍Filter的开发、使用以及讨论他们的执行顺序。

    一、Filter的使用

             在默认的WebApi中,框架提供了三种Filter,他们的功能和运行条件如下表所示:

    Filter 类型

    实现的接口

    描述

    Authorization

    IAuthorizationFilter

    最先运行的Filter,被用作请求权限校验

    Action

    IActionFilter

    在Action运行的前、后运行

    Exception

    IExceptionFilter

    当异常发生的时候运行

    1.授权拦截过滤器

    首先,我们实现一个CustomAuthorizeAttribute可以用以简单的权限控制,(此处AuthorizeAttribute继承自AuthorizationFilterAttribute)用于接口授权:

    /// <summary>
        /// 自定义授权
        /// </summary>
         [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
        public class CustomAuthorizeAttribute:AuthorizeAttribute
        {
           /// <summary>
           /// 用户授权
           /// </summary>
           /// <param name="actionContext"></param>
           /// <returns></returns>
            public override void OnAuthorization(HttpActionContext actionContext)
            {
                //url获取token  
                var content = actionContext.Request.Properties["MS_HttpContext"] as HttpContextBase;
                HttpRequestBase request = content.Request;
                string access_key = request.Params["access_key"];//不管是post请求还是get请求,都从地址栏获取key跟sign
                string sign = request.Params["sign"];
                //校验IP
                var data=XmlUtil.IsAuthorization(HttpContext.Current.Request.UserHostAddress);
                if (data.IsExistence)//ip是否在白名单内
                {
                    if ("1".Equals(data.IsAuthorization))//是否需要参与签名验证
                    {
                        if (!string.IsNullOrEmpty(access_key) && !string.IsNullOrEmpty(sign))
                        {
                            var key = "7058e63cdf0646948201";//随便固定一个key,真实使用的化可以从数据库获取或配置文件读取
                            var s = MD5Encrypt32(string.Format("{0}{1}", access_key, key));
                            if ("2c3a368b-26a8-4a4d-a204-14bd6388f3c2".Equals(access_key) && s.Equals(sign))//验证通过放行
                            {
                                base.IsAuthorized(actionContext);
                            }
                            else
                            {
                                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new
                                {
                                    code = HttpStatusCode.Unauthorized,
                                    data = "",
                                    message = "access_key 或 sign 参数有误,请核对",
                                });
                            }
                        }
                        else
                        {
                            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new
                            {
                                code = HttpStatusCode.Unauthorized,
                                data = "",
                                message = "access_key 或 sign 校验参数未从地址栏带入,请核对",
                            });
                        }
                    }
                    else
                    {
                        base.IsAuthorized(actionContext);
                    }
                }
                else
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new
                    {
                        code = HttpStatusCode.Unauthorized,
                        data = "",
                        message = $"IP:{HttpContext.Current.Request.UserHostAddress}没有调用服务的权限",
                    });
                }
            }
           /// <summary>
           /// 32位MD5加密
           /// </summary>
           /// <param name="password"></param>
           /// <returns></returns>
           public  string MD5Encrypt32(string password)
           {
               string pwd = "";
               MD5 md5 = MD5.Create(); //实例化一个md5对像
               // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 
               byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
               // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
               for (int i = 0; i < s.Length; i++)
               {
                   // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 
                   pwd = pwd + s[i].ToString("X");
               }
               return pwd.ToLower();
           }
        }

     2.错误异常捕获过滤器

    当服务端代码报错或出异常时,可自定义设置固定格式的异常返回给调用者,具体实现如下:

    /// <summary>
        /// 自定义错误异常捕获
        /// </summary>
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
        public class CustomExceptionAttribute:ExceptionFilterAttribute
        {
            /// <summary>
            /// 异常发生
            /// </summary>
            /// <param name="actionExecutedContext"></param>
            public override void OnException(HttpActionExecutedContext actionExecutedContext)
            {
                //记录错误日志
                Task.Run(() =>
                {
                    //此处可以调用记录日志方法
                });
                actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError, new
                {
                    code = HttpStatusCode.InternalServerError,
                    message = actionExecutedContext.Exception.Message
                });
            }
        }

     3.请求成功过滤器

    如果要把所有接口返回类型参数固定可以使用ActionFilter过滤器,简单实现如下:

    /// <summary>
        /// 自定义统一信息格式返回
        /// </summary>
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
        public class CustomActionAttribute:ActionFilterAttribute
        {
            /// <summary>
            /// 请求成功之后
            /// </summary>
            /// <param name="actionExecutedContext"></param>
            public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
            {
                actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(actionExecutedContext.Response.StatusCode, new
                {
                    code = 200,
                    data =JsonConvert.DeserializeObject(actionExecutedContext.Response.Content.ReadAsStringAsync().Result),//返回给调用者的数据
                    message ="success"
                });
            }
        }

    接口调用成功之后返回给调用者的数据格式都是固定格式,调用者使用起来就很方便,返回固定格式如下:

    {
       code = 200,
       data ="数据"
       message ="success"
    }

     二、过滤器的使用及注册

    过滤器注册方式有三种:

    • 全局注册
    • 类注册
    • 方法注册

    1.全局注册

    全局注册时在App_Start==>WebApiConfig.cs文件里面,注册代码如下:

    public static class WebApiConfig
        {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="config"></param>
            public static void Register(HttpConfiguration config)
            {
                // 身份认证筛选器。
                config.Filters.Add(new CustomAuthorizeAttribute());//这是全局注册
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                config.EnsureInitialized();
            }
        }

    2.控制器注册

    控制器注册就是在Controller类里面进行注册,注册代码如下:

    /// <summary>
    /// 
    /// </summary>
    [CustomAuthorizeAttribute] //控制器注册
    public class DepartmentApiController : ApiController {
    
    
    
     } 

    3.方法注册

    方法注册就是在Controller里面使用的方法上进行标记注册,注册代码如下:

    /// <summary>
    /// 
    /// </summary>
    public class DepartmentApiController : ApiController {
    
     [CustomAuthorizeAttribute]//方法注册
     [HttpGet]
      public object GetDepartmentList()
      {
    
      }
    }

    三、过滤器执行优先级

      [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple = false)]//AllowMultiple=false时 执行优先级如下 

    同一个过滤器分别用在了全局、控制器和行为方法中,执行同一个方法时都会有先后顺序,如果按默认值(不设Order的情况下),一般的顺序是由最外层到最里层,就是“全局”——>“控制器”——>“行为方法”;

    而特别的就是错误处理的过滤器,由于异常是由里往外抛的,所以它的顺序刚好也反过来:“行为方法”——>“控制器”——>“全局”。

    以上是开发webapi过滤器的简单用法,以上代码还需要优化,有需要的朋友自己封装优化一下就可以使用了。

  • 相关阅读:
    quora 中有关angular与emberjs的精彩辩论
    迷你MVVM框架 avalonjs 0.94发布
    重写自己,减少判断 ---- 引发的思考
    JSON数据的优化
    记录全局错误
    Bat相关的项目应用
    C#中如何实现json转化时只处理部分属性
    JSON数据的处理中的特殊字符
    C# .net中json字符串和对象之间的转化方法
    VS调试 ---- 监视窗口、即时窗口、输出窗口
  • 原文地址:https://www.cnblogs.com/jiangxifanzhouyudu/p/9093147.html
Copyright © 2011-2022 走看看