有些时候,为了防止我们上线的网站被攻击,或者被刷取流量,我们会对某一个ip进行限制处理,这篇文章,我们将通过Spring Boot编写一个小案例,来实现在一分钟内同一个IP只能访问10次,当然具体数值,是您来决定,废话不多说,上代码。
首先,我们需要在Spring Boot的pom.xml文件中插入我们需要的依赖。具体的依赖部分我给出如下,也是Spring Boot常用的依赖,当然我并未在pom文件中给出Spring Boot的使用版本,因为我觉得并不是每个人都使用同样的版本,这是我使用的:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
既然说到是对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;
}
}
在这段代码中,我们使用了一个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);
}
}
在本段代码中,我们通过构造函数注入 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;
}
}
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;
}
}
最终结果展示: