• 使用Spring Boot限制在一分钟内某个IP只能访问10次


    有些时候,为了防止我们上线的网站被攻击,或者被刷取流量,我们会对某一个ip进行限制处理,这篇文章,我们将通过Spring Boot编写一个小案例,来实现在一分钟内同一个IP只能访问10次,当然具体数值,是您来决定,废话不多说,上代码。

    首先,我们需要在Spring Boot的pom.xml文件中插入我们需要的依赖。具体的依赖部分我给出如下,也是Spring Boot常用的依赖,当然我并未在pom文件中给出Spring Boot的使用版本,因为我觉得并不是每个人都使用同样的版本,这是我使用的:
    在这里插入图片描述

    <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starterartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintagegroupId>
                        <artifactId>junit-vintage-engineartifactId>
                    exclusion>
                exclusions>
            dependency>
            <dependency>
                <groupId>org.apache.tomcat.embedgroupId>
                <artifactId>tomcat-embed-coreartifactId>
            dependency>
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-webmvcartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-webartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    既然说到是对ip访问的限制,那么我们可以通过拦截器来实现对同一个ip地址在同一段时间段内的多次访问进行限制。具体代码如下:

    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /**
     * @author Miaow.Y.Hu
     * @date 2023年10月24日 19:01
     * @description
     */
    
    
    @Component
    public class RateLimitInterceptor implements HandlerInterceptor {
    
        private static final int MAX_REQUESTS = 10; // 同一时间段内允许的最大请求数
        private static final long TIME_PERIOD = 60 * 1000; // 时间段,单位为毫秒 在一分钟内限制ip访问次数为10次
    
        private Map<String, Integer> requestCounts = new HashMap<>();
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String ipAddress = request.getRemoteAddr();
            System.out.println(ipAddress);
            // 检查 IP 地址是否已经达到最大请求数
            if (requestCounts.containsKey(ipAddress) && requestCounts.get(ipAddress) >= MAX_REQUESTS) {
                response.setStatus(429); //设置响应状态码
                response.getWriter().write("Too many requests from this IP address");
                return false;
            }
    
            // 更新 IP 地址的请求数
            requestCounts.put(ipAddress, requestCounts.getOrDefault(ipAddress, 0) + 1);
    
            // 在指定时间后清除 IP 地址的请求数
            new Timer().schedule(
                    new TimerTask() {
                        @Override
                        public void run() {
                            requestCounts.remove(ipAddress);
                        }
                    },
                    TIME_PERIOD
            );
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在这段代码中,我们使用了一个Map来存储每个IP地址的请求数,在preHandle方法中,我们首先检查IP地址的请求数是否已经达到最大请求数,如果是,则返回一个429当前IP地址的请求次数太多,一分钟只能请求10次,当然这决定权在你,然后我们更新IP地址的请求数,并在指定的时间段后清除该IP地址的请求数。

    接下来,我们需要在配置类中注册拦截器,我采用的事WebMvcConfig:

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
    
        private final RateLimitInterceptor rateLimitInterceptor;
    
        @Autowired
        public WebMvcConfig(RateLimitInterceptor rateLimitInterceptor) {
            this.rateLimitInterceptor = rateLimitInterceptor;
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(rateLimitInterceptor);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在本段代码中,我们通过构造函数注入 RateLimitInterceptor,然后在 addInterceptors 方法中将拦截器添加到拦截器注册表中。

    现在,当同一 IP 地址在同一时间段内的请求数达到最大限制时,它将收到一个 429的响应。你可以根据自己的需求调整最大请求数和时间段。

    需要注意的是,这个小案例只是简答实现了对IP地址的拦截,在实际开发中,我们需要做的东西更加多,考虑的情况也需要更加全面,利用更加复杂的逻辑和持久化的存储来处理IP地址的请求限制。

    接下来,我们通过Controller类来测试我们的写的案例是否实现这个功能:

    @RestController
    @RequestMapping("user/")
    public class UserController {
    
        @RequestMapping("demo")
        public String test(){
            return "测试";
        }
    
        @RequestMapping("userDemo")
        public User userDemo(User user){
            return  user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    User其实可写可不写,但是便于重复利用,我这里给出User的实体类吧:

    public class User {
        private Long id;
        private String name;
        private Integer age;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            User user = (User) o;
            return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(id, name, age);
        }
    
        public User() {
        }
    
        public User(Long id, String name, Integer age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    最终结果展示:
    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    Unity json反序列化为 字典存储
    计算机程序设计艺术习题解答(Excercise 1.2.2-27题)- 求对数标准算法的有限精度误差估计
    数据结构-插入排序+希尔排序+选择排序
    分布式文件存储系统FastDFS[2]-上传和下载文件工具类
    《运营之光3.0》全新上市——跨越时代,自我颠覆的诚意之作
    iOS代码混淆教程
    【SSL证书安全】
    见缝插针游戏针不会更着上面旋转的小球运动
    工商管理论文要怎么写?
    【MySQL】数据库服务器硬件优化与实战详解(调优篇)(实战篇)(MySQL专栏启动)
  • 原文地址:https://blog.csdn.net/qq_45922256/article/details/134019827