1.場景描述
在日常開發接口的時候,尤其是restfull接口,肯定會考慮安全或者是做一些自定義的限制,用來界定並維護代碼。那么,我們都會采用什么方法那?通常來講,我們可以通過session的形式,以訪問者的ip為鍵來記錄用戶對某接口訪問的次數,並對其作出限制。在.net中還可以將session或者是MemoryCache來替換session來實現(另外也可以用第三方nosql:如redis、Mongodb等)。本文結合redis予以實現。
2.實現分析
通常來說,我們會可以在每一個需要被限制的接口使用redis來存儲記錄當前來訪客戶端訪問的次數,這樣,便可以實現我們想要的效果。但是,少啦可以,如果說,日后很多接口都需要限制該怎么辦吶,我們該如何去整理並統籌規划吶?答案就是:可以采用Action過濾器標簽的的形式,這樣,我們只需封裝這樣可以限制訪問的一個公用的過濾器標簽,在需要被限制的地方加上標簽,便可以得到我們想要的效果。廢話不多說,直接上代碼!!!
1 public class ApiLimitFilter : ActionFilterAttribute 2 { 3 #region 可配參數 4 //標識前綴(唯一) 5 private string redisKeyPrefix; 6 public string RedisKeyPrefix 7 { 8 get 9 { 10 if (string.IsNullOrEmpty(redisKeyPrefix)) 11 { 12 redisKeyPrefix = "Api_limit"; 13 } 14 15 return redisKeyPrefix; 16 } 17 set { redisKeyPrefix = value; } 18 } 19 //顯示時間長度 20 private TimeSpan? timeSpan { get; set; } 21 public TimeSpan? TimeSpan 22 { 23 get 24 { 25 if (timeSpan == null) 26 { 27 timeSpan = System.TimeSpan.FromDays(1); 28 } 29 return timeSpan; 30 } 31 set { timeSpan = value; } 32 } 33 //顯示次數 34 private int limitCount; 35 public int LimitCount 36 { 37 get 38 { 39 if (limitCount <= 0) 40 { 41 limitCount = 5; 42 } 43 44 return limitCount; 45 } 46 set { limitCount = value; } 47 } 48 //提示語 49 private string notify; 50 public string Notify 51 { 52 get 53 { 54 if (string.IsNullOrEmpty(notify)) 55 { 56 notify = "請求受限"; 57 } 58 59 return notify; 60 } 61 set { notify = value; } 62 } 63 #endregion 64 #region 內部私用 65 private string RedisKey 66 { 67 get { return string.Format("{0}_{1}", redisKeyPrefix, IpUtil.GetHostAddress()); } 68 } 69 private int currentCount = 0; 70 #endregion 71 #region Limit 72 /// <summary> 73 /// 限制過濾 74 /// </summary> 75 /// <param name="actionContext"></param> 76 public override void OnActionExecuting(HttpActionContext actionContext) 77 { 78 //獲取接口訪問次數(redis封裝的工具類/可切換自己想要的東西) 79 currentCount = RedisCacheHelper.Instance.Get<int>(RedisKey); 80 if (currentCount > LimitCount) 81 { 82 var resultModel = new ResultModel(200, Notify); 83 actionContext.Response=actionContext.Request.CreateResponse(HttpStatusCode.OK, resultModel); 84 85 } 86 base.OnActionExecuting(actionContext); 87 } 88 /// <summary> 89 /// 限制追記 90 /// </summary> 91 /// <param name="actionExecutedContext"></param> 92 public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 93 { 94 currentCount++; 95 //記住訪問痕跡(redis封裝的工具類/可切換自己想要的東西) 96 RedisCacheHelper.Instance.Set(RedisKey, currentCount, TimeSpan); 97 base.OnActionExecuted(actionExecutedContext); 98 } 99 #endregion 100 }
