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 }