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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM