点击下载《Java Spring Boot实现基于URL + IP访问频率限制(源代码)》
1. 引言
在现代 Web 应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段。为了保护系统资源,防止服务器过载或服务不可用,需要对接口的访问频率进行限制。本文将介绍如何使用 Spring Boot 实现基于 URL 和 IP 的访问频率限制,具体步骤包括:
-
使用拦截器拦截请求:在每个请求到达控制器之前进行拦截。
-
使用 Redis 存储访问记录:利用 Redis 的高性能特性来存储每个 IP 对每个 URL 的访问次数。
-
检测访问频率:判断 IP 在一定时间内对特定 URL 的访问次数是否超过限制。
-
禁用恶意 IP:如果超过限制,则将 IP 列入黑名单,禁止其后续访问。
2. 项目依赖
首先,在 pom.xml
中添加必要的依赖,包括 Spring Boot Web、Spring Boot Starter Data Redis 和 Lombok(用于简化代码)。
<!-- Spring Boot Starter Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- Lombok (可选,用于简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
3. 配置 Redis
在 application.properties
中配置 Redis 连接信息:
server.port=8080
# Redis 配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=0
# 可选:设置密码
# spring.redis.password=yourpassword
或在 application.yml
中配置Redis连接信息:
server:
port: 8080
spring:
application:
name: urlInterceptorDemo
data:
# redis 配置
redis:
# 地址
host: 127.0.0.1
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password: "123456"
# 连接超时时间
timeout: 10s
4. 创建拦截器
创建一个拦截器 RateLimitInterceptor
,用于拦截每个请求并执行访问频率限制逻辑。
package com.yyqq.urlinterceptordemo.Interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.concurrent.TimeUnit;
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
@Autowired
public RedisTemplate redisTemplate;
// 访问频率限制:每个 IP 每个 URL 最多访问 100 次 / 分钟
private static final int MAX_REQUESTS = 10;
private static final int TIME_WINDOW = 60; // 秒
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ip = getClientIP(request);
String url = request.getRequestURI();
String key = "rate_limit:" + url + ":" + ip;
long count = redisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
// 设置键的过期时间为 TIME_WINDOW 秒
redisTemplate.expire(key, TIME_WINDOW, TimeUnit.SECONDS);
}
if (count > MAX_REQUESTS) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("请求过于频繁,请稍后再试。");
return false;
}
return true;
}
private String getClientIP(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
代码说明
- RedisTemplate:用于与 Redis 进行交互。
- MAX_REQUESTS 和 TIME_WINDOW:定义每个 IP 在每个 URL 上的最大访问次数和时间窗口(60 秒)。
- preHandle 方法:
- 获取客户端 IP 和请求的 URL。
- 构建 Redis 键,例如
rate_limit:/api/data:192.168.1.1
。 - 使用
increment
方法对键进行递增,并设置过期时间。 - 如果访问次数超过
MAX_REQUESTS
,则返回 403 状态码,并返回错误信息。
- getClientIP 方法:获取客户端的真实 IP,处理代理和负载均衡的情况。
5. 注册拦截器
创建一个配置类 WebConfig
,将拦截器注册到 Spring MVC 中。
package com.yyqq.urlinterceptordemo.config;
import com.yyqq.urlinterceptordemo.Interceptor.RateLimitInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RateLimitInterceptor rateLimitInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(rateLimitInterceptor)
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns("/error"); // 排除错误路径
}
}
代码说明
- addInterceptors 方法:将自定义的拦截器添加到拦截器链中,并指定拦截的路径模式。
- addPathPatterns("/")**:拦截所有路径。
- excludePathPatterns(“/error”):排除错误路径,避免拦截器影响错误处理。
6. 创建控制器
创建一个简单的控制器 DemoController
,包含一个示例接口用于测试。
package com.yyqq.urlinterceptordemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class DemoController {
@GetMapping("/getData")
public String getData() {
return "这是数据接口,现在访问正常!";
}
}
8. 测试
启动 Spring Boot 应用后,可以进行以下测试:
1.正常访问:
-
访问
http://localhost:8080/test/getData
,应返回 “这是数据接口,现在访问正常!”。 -
多次快速刷新,访问次数达到 10 次后,应返回 “请求过于频繁,请稍后再试。”,并返回 403 状态码。
2.禁用 IP:
-
在达到限制后,等待一段时间(60 秒),再次访问应恢复正常。
9. 总结
通过结合使用 Spring Boot 拦截器和 Redis,本文实现了一种基于 URL 和 IP 的访问频率限制机制。这种机制能够有效地防止接口被恶意刷新和暴力请求,保护系统资源,提高应用的安全性和稳定性。在实际应用中,可以根据具体需求调整访问频率限制的参数,如最大访问次数和时间窗口。此外,还可以结合其他安全措施,如 IP 黑名单、验证码等,进一步增强系统的防护能力。
点击下载《Java Spring Boot实现基于URL + IP访问频率限制(源代码)》
标签:IP,Java,ip,org,Boot,springframework,访问,Spring,import From: https://blog.csdn.net/a342874650/article/details/144989766