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常用代码,自己封装一下就可以使用了

猜你喜欢

转载自www.cnblogs.com/zhaoshujie/p/9765268.html