API介面都是提供給第三方服務/客戶端呼叫,所有請求地址以及請求引數都是暴露給使用者的。
每次請求一個HTTP請求,使用者都可以透過F12,或者抓包工具看到請求的URL連結,然後copy出來。這樣是非常不安全的,有人可能會惡意的刷我們的介面,那這時該怎麼辦呢?
增加一個全域性過濾器 獲取客戶端的IP 限制固定時間內的訪問次數即可
第一步:建立全域性過濾器 RateLimitFilter
public class RateLimitFilter : ActionFilterAttribute { private const int MaxRequests = 30; //1分鐘訪問最大頻率 private bool StartUp = true; //是否啟用 public override void OnActionExecuting(ActionExecutingContext context) { if (StartUp) { base.OnActionExecuting(context); string clientId = GetIP(); if (GetCache(clientId) == null) { SetCacheRelativeTime(clientId, 1, 60); } else { var cs = int.Parse(GetCache(clientId).ToString()); SetCacheRelativeTime(clientId, cs += 1, 60); } //var x = int.Parse(GetCache(clientId).ToString()); if (int.Parse(GetCache(clientId).ToString()) > MaxRequests) { //返回值規範不統一 context.Result = new ContentResult { Content = "<script type='text/javascript'>alert('" + clientId + " 訪問過於頻繁,請稍等片刻!');</script><h1 style='text-align: center; color: red;'>" + clientId + " 訪問過於頻繁,請稍等片刻!<h1>" }; //返回值規範統一 前端有錯誤提示 //context.Result = new JsonResult() //{ // Data = new { Result = false, status = false, suc = false, message = "" + clientId + " 訪問過於頻繁,請稍等片刻!" }, // JsonRequestBehavior = JsonRequestBehavior.AllowGet //}; } } } /// <summary> /// 獲取客戶端IP地址 /// </summary> /// <returns>若失敗則返回回送地址</returns> public static string GetIP() { //如果客戶端使用了代理伺服器,則利用HTTP_X_FORWARDED_FOR找到客戶端IP地址 string userHostAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrEmpty(userHostAddress)) { userHostAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString().Split(',')[0].Trim(); } //否則直接讀取REMOTE_ADDR獲取客戶端IP地址 if (string.IsNullOrEmpty(userHostAddress)) { userHostAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } //前兩者均失敗,則利用Request.UserHostAddress屬性獲取IP地址,但此時無法確定該IP是客戶端IP還是代理IP if (string.IsNullOrEmpty(userHostAddress)) { userHostAddress = HttpContext.Current.Request.UserHostAddress; } //最後判斷獲取是否成功,並檢查IP地址的格式(檢查其格式非常重要) if (!string.IsNullOrEmpty(userHostAddress) && IsIP(userHostAddress)) { return userHostAddress; } return "127.0.0.1"; } /// <summary> /// 檢查IP地址格式 /// </summary> /// <param name="ip"></param> /// <returns></returns> public static bool IsIP(string ip) { return System.Text.RegularExpressions.Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); } #region 設定相對過期時間Cache值(即:訪問啟用後不過期) /// <summary> /// 設定相對過期時間Cache值(即:訪問啟用後不過期) /// </summary> /// <param name="objectkey"></param> /// <param name="objObject"></param> /// <param name="timeSpan">超過多少時間不呼叫就失效,單位是秒</param> public static void SetCacheRelativeTime(string objectkey, object objObject, int timeSpan) { System.Web.Caching.Cache objCache = HttpRuntime.Cache; objCache.Insert(objectkey, objObject, null, DateTime.MaxValue, TimeSpan.FromSeconds(timeSpan)); } #endregion #region 獲取當前應用程式指定CacheKey的Cache值 /// <summary> /// 獲取當前應用程式指定CacheKey的Cache值 /// </summary> /// <param name="CacheKey"></param> /// <returns></returns>y public static object GetCache(string CacheKey) { try { System.Web.Caching.Cache objCache = HttpRuntime.Cache; Object value = objCache[CacheKey]; if (value != null) { return value; } else { return null; } } catch (Exception) { return null; } } #endregion }
第二步:FilterConfig
類並註冊你的全域性過濾器
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new RateLimitFilter()); // 過濾器 } }
第三步:Global.asax 檔案中註冊全域性過濾器
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); UnityConfig.RegisterComponents(); // 註冊全域性過濾器 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); }