当前位置:   article > 正文

springboot项目通过ip和url限制用户请求次数_springboot 限制请求频率

springboot 限制请求频率

项目背景

前段时间公司服务器被攻击,防火墙显示一个南京的ip一天访问接口20w+次,一下子把数据库cpu搞到00%,临时解决办法是把该ip通过防火墙访问策略禁止访问了,为了防止后期还有恶意攻击,我们在项目中新增一个拦截器,根据用户访问的ip和资源请求的url限制其访问频率。

项目介绍

通过拦截器,我们设置了1分钟内同一个ip和ur如果请求超过25次就提醒超过了限定的次数

 

 

创捷拦截器

  1. package com.brickdog.filter;
  2. import com.brickdog.common.utils.CacheUtils;
  3. import com.brickdog.common.utils.RequestLimit.HttpUtil;
  4. import com.brickdog.common.utils.RequestLimit.RequestLimitException;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.servlet.HandlerInterceptor;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. @Slf4j
  11. @Component
  12. public class RequestLimitInterceptor implements HandlerInterceptor {
  13. @Override
  14. public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws RequestLimitException {
  15. try {
  16. Integer limit_count = 25;
  17. Integer limit_time = 1000 *60;
  18. String ip = HttpUtil.getIpByRequest(httpServletRequest);
  19. String url = httpServletRequest.getRequestURL().toString();
  20. String key = "req_limit_".concat(url).concat(ip);
  21. String cache = (String)CacheUtils.get(key);
  22. if (null == cache) {
  23. String value = "1_" + System.currentTimeMillis();
  24. CacheUtils.put(key,value,limit_time);
  25. } else {
  26. String value = (String) cache;
  27. String[] s = value.split("_");
  28. int count = Integer.parseInt(s[0]);
  29. if (count > limit_count) {
  30. log.info("用户IP[{}], 访问地址[{}], 超过了限定的次数[{}]", ip, url, limit_count);
  31. throw new RequestLimitException();
  32. }
  33. value = (count + 1) + "_" + s[1];
  34. long last = limit_time - (System.currentTimeMillis() - Long.parseLong(s[1]));
  35. if (last > 0) {
  36. CacheUtils.put(key,value,limit_time);
  37. }
  38. }
  39. } catch (RequestLimitException e) {
  40. throw e;
  41. } catch (Exception e) {
  42. log.error("发生异常", e);
  43. }
  44. return true;
  45. }
  46. }

注册拦截器

  1. package com.brickdog.config;
  2. import com.brickdog.filter.AuthHandlerInterceptor;
  3. import com.brickdog.filter.RequestLimitInterceptor;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  7. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  8. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  9. /**
  10. * @author brickdog
  11. * @version 1.0
  12. * @create 2022/2/4 21:24
  13. */
  14. @Configuration
  15. public class AuthConfigurer implements WebMvcConfigurer {
  16. @Autowired
  17. RequestLimitInterceptor requestLimitInterceptor;
  18. @Override
  19. public void addInterceptors(InterceptorRegistry registry) {
  20. registry.addInterceptor(requestLimitInterceptor);
  21. }
  22. }

Cache缓存类

  1. package com.brickdog.common.utils;
  2. import java.util.Map;
  3. import java.util.concurrent.*;
  4. public class CacheUtils {
  5. // 键值对集合
  6. private final static Map<String, Entity> map = new ConcurrentHashMap<>();
  7. // 定时器线程池, 用于清除过期缓存
  8. private final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
  9. /**
  10. * 添加缓存
  11. */
  12. public synchronized static void put(String key, Object data) {
  13. CacheUtils.put(key, data, 0);
  14. }
  15. /**
  16. * 添加缓存
  17. * 过期时间: 单位毫秒, 0表示无限长
  18. */
  19. public synchronized static void put(String key, Object data, long expire) {
  20. // 清除原键值对
  21. CacheUtils.remove(key);
  22. // 设置过期时间
  23. if (expire > 0) {
  24. Future future = executor.schedule(() -> {
  25. // 过期后清除该键值对
  26. synchronized (CacheUtils.class) {
  27. map.remove(key);
  28. }
  29. }, expire, TimeUnit.MILLISECONDS);
  30. map.put(key, new Entity(data, future));
  31. } else {
  32. // 不设置过期时间
  33. map.put(key, new Entity(data, null));
  34. }
  35. }
  36. /**
  37. * 读取缓存
  38. */
  39. public synchronized static Object get(String key) {
  40. Entity entity = map.get(key);
  41. return entity == null ? null : entity.getValue();
  42. }
  43. /**
  44. * 读取缓存
  45. * clazz 值类型
  46. */
  47. public synchronized static <T> T get(String key, Class<T> clazz) {
  48. return clazz.cast(CacheUtils.get(key));
  49. }
  50. /**
  51. * 清除指定缓存
  52. * 返回值为指定key的value
  53. */
  54. public synchronized static Object remove(String key) {
  55. // 清除指定缓存数据
  56. Entity entity = map.remove(key);
  57. if (entity == null)
  58. return null;
  59. // 清除指定键值对定时器
  60. Future future = entity.getFuture();
  61. if (future != null)
  62. future.cancel(true);
  63. return entity.getValue();
  64. }
  65. /**
  66. * 清除所有缓存
  67. */
  68. public synchronized static void removeAll() {
  69. map.clear();
  70. }
  71. /**
  72. * 查询当前缓存的键值对数量
  73. */
  74. public synchronized static int size() {
  75. return map.size();
  76. }
  77. /**
  78. * 缓存实体类
  79. */
  80. private static class Entity {
  81. // 键值对的value
  82. private Object value;
  83. // 定时器的future
  84. private Future future;
  85. /**
  86. * 创建实体类
  87. */
  88. public Entity(Object value, Future future) {
  89. this.value = value;
  90. this.future = future;
  91. }
  92. /**
  93. * 获取value值
  94. */
  95. public Object getValue() {
  96. return value;
  97. }
  98. /**
  99. * 获取future对象
  100. */
  101. public Future getFuture() {
  102. return future;
  103. }
  104. }
  105. }

pom坐标

  1. <!-- 日志 -->
  2. <dependency>
  3. <groupId>org.slf4j</groupId>
  4. <artifactId>slf4j-api</artifactId>
  5. <version>1.7.30</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.projectlombok</groupId>
  9. <artifactId>lombok</artifactId>
  10. <version>1.18.16</version>
  11. </dependency>
  12. <!-- 日志 -->

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/874268
推荐阅读
相关标签
  

闽ICP备14008679号