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);
- }