• 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

    当异常发生的时候运行

           首先,我们实现一个AuthFilterOutside可以用以简单的权限控制:

    public class AuthFilterOutside: AuthorizeAttribute
    {
       private SP_PortUserBLL sp_portuserbll = new SP_PortUserBLL();
       //重写基类的验证方式,加入我们自定义的Ticket验证 
       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.Form["access_key"];//获取请求参数对应的值
           string sign = request.Form["sign"];
           if (!string.IsNullOrEmpty(access_key) && !string.IsNullOrEmpty(sign))
           {
               //解密用户ticket,并校验用户名密码是否匹配 
               if (ValidateTicket(access_key, sign))
               {
                   base.IsAuthorized(actionContext);
               }
               else
               {
                   HandleUnauthorizedRequest(actionContext);
               }
           }
           //如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401
           else
           {
               var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
               bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);
               if (isAnonymous) base.OnAuthorization(actionContext);
               else HandleUnauthorizedRequest(actionContext);
           }
       }
       //校验sign(数据库数据匹配) 
       private bool ValidateTicket(string key,string sign)
       {
           var result=sp_portuserbll.GetAccess_secret(key);
           if (!string.IsNullOrEmpty(result))
           {
               var mysing= Encryption.DataEncryption(key, result);//sign验证
               if (mysing.Equals(sign))
               {
                   return true;
               }
               return false;
           }
           return false;
       }
    }

    当请求地址里面包含  access_key 和  sign  对应的键值对,获取对应的值与数据库数据进行匹配,匹配通过后可请求数据,适用于get 、post请求。

     

    接口请求成功后记录日志的实现

    /// <summary>
    /// 请求成功后触发
    /// </summary>
    public class AuthFilter: ActionFilterAttribute
    {
       private PortLogBLL portlogbll = new PortLogBLL();
       public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
       {
           //action 请求之后触发<br>            //日志记录 访问量记录等等
           portlogbll.SaveForm(new PortLogEntity()
           {
               PortName = actionExecutedContext.Request.RequestUri.AbsolutePath,//获得调用接口,
               RequestType = actionExecutedContext.Request.Method.ToString(),
               StatusCode = Convert.ToInt32(new HttpResponseMessage(HttpStatusCode.OK).StatusCode),//设置状态码
               ClientIp = GetClientIp(),
               ParameterList = actionExecutedContext.ActionContext.ActionArguments.ToJson(),//获得参数值
               Success = true
           });
       }
       /// <summary>
       /// 获取客户端Ip
       /// </summary>
       /// <returns></returns>
       private string GetClientIp()
       {
           string result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
           if (string.IsNullOrEmpty(result))
           {
               result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
           }
           if (string.IsNullOrEmpty(result))
           {
               result = HttpContext.Current.Request.UserHostAddress;
           }
           if (string.IsNullOrEmpty(result))
           {
               return "0.0.0.0";
           }
           return result;
       }
    }

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

    /// <summary>
    /// 接口发生异常过滤器
    /// </summary>
    public class ExceptionHandling : ExceptionFilterAttribute, IExceptionFilter
    {
       private PortLogBLL portlogbll = new PortLogBLL();
       public override void OnException(HttpActionExecutedContext actionExecutedContext)
       {
           var code = new HttpResponseMessage(HttpStatusCode.InternalServerError).StatusCode;//设置错误代码:例如:500 404
           actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
           string msg = JsonConvert.SerializeObject(new BaseResult() { success = false, message = actionExecutedContext.Exception.Message });//返回异常错误提示
                                                                                                                                             //写入错误日志相关实现
           portlogbll.SaveForm(new PortLogEntity()
           {
               PortName = actionExecutedContext.Request.RequestUri.AbsolutePath,
               RequestType = actionExecutedContext.Request.Method.ToString(),
               StatusCode = Convert.ToInt32(code),
               ClientIp = GetClientIp(),
               ParameterList = actionExecutedContext.ActionContext.ActionArguments.ToJson(),
               Success = false,
               ErrorMessage = msg
           });
           //result
           actionExecutedContext.Response.Content = new StringContent(msg, Encoding.UTF8);
       }
       /// <summary>
       /// 获取调用接口者ip地址
       /// </summary>
       /// <returns></returns>
       private string GetClientIp()
       {
           string result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
           if (string.IsNullOrEmpty(result))
           {
               result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
           }
           if (string.IsNullOrEmpty(result))
           {
               result = HttpContext.Current.Request.UserHostAddress;
           }
           if (string.IsNullOrEmpty(result))
           {
               return "0.0.0.0";
           }
           return result;
       }
    }
    public class BaseResult
    {
       /// <summary>
       /// 状态
       /// </summary>
       public bool success { get; set; }
       /// <summary>
       /// 错误信息
       /// </summary>
       public string message { get; set; }
    }

    以上是开发webapi常用代码,自己封装一下就可以使用了

  • 相关阅读:
    5月编程语言排行榜:动态语言的前世今生
    编程语言范式
    面向函数范式编程(Functional programming)
    bash脚本测试总结
    BASH的保护性编程技巧
    汇编Shellcode的技巧
    FreeBSD上编写x86 Shellcode初学者指南
    CnAms and cndoc
    Linux下shellcode的编写
    How To Configure NetScaler AppFlow for SolarWinds
  • 原文地址:https://www.cnblogs.com/zhaoshujie/p/9765268.html
Copyright © 2020-2023  润新知