通过Interceptor以及Redis实现接口访问防刷

news/2024/12/13 0:50:10/

方式一

以下是通过Interceptor以及Redis实现接口访问防刷的Java代码示例:

首先,创建一个自定义拦截器类,实现HandlerInterceptor接口,并在preHandle方法中添加接口防刷逻辑。例如:

@Component
public class RateLimiterInterceptor implements HandlerInterceptor {private static final String RATE_LIMITER_KEY_PREFIX = "rate_limiter:";private static final int MAX_REQUESTS_PER_SECOND = 10;private final RedisTemplate<String, String> redisTemplate;@Autowiredpublic RateLimiterInterceptor(RedisTemplate<String, String> redisTemplate) {this.redisTemplate = redisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String ip = request.getRemoteAddr();String key = RATE_LIMITER_KEY_PREFIX + ip;Long count = redisTemplate.opsForValue().increment(key, 1);if (count == 1) {// Set a TTL to the key so it gets deleted after one second.redisTemplate.expire(key, 1, TimeUnit.SECONDS);}if (count > MAX_REQUESTS_PER_SECOND) {response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());return false;}return true;}
}

上述代码中,我们使用了Redis作为存储桶,每个IP地址对应一个key,每一次请求就将key中的计数器加一,并设置一个过期时间为1秒钟。如果计数器超过最大请求数,则返回HTTP 429 Too Many Requests响应。

接下来,在Spring Boot应用程序中配置拦截器,例如:

@Configuration
public class WebConfig implements WebMvcConfigurer {private final RateLimiterInterceptor rateLimiterInterceptor;@Autowiredpublic WebConfig(RateLimiterInterceptor rateLimiterInterceptor) {this.rateLimiterInterceptor = rateLimiterInterceptor;}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimiterInterceptor);}
}

这样,我们就可以实现接口访问防刷功能了。每个IP地址在1秒钟内最多只能发送10个请求。如果超过限制,则返回HTTP 429响应。

方式二

以下是通过Interceptor以及Redis 自定义注解 + 反射 实现接口访问防刷的Java代码示例:

首先,创建一个自定义注解@RateLimit,并在注解中添加限制参数。例如:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {int limit() default 10;int timeout() default 1;
}

然后,在服务启动时,使用反射扫描所有带有@RateLimit注解的方法,并生成对应的拦截器和key。例如:

@Component
public class RateLimiterBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {private final Map<Method, String> rateLimiterMap = new HashMap<>();private ApplicationContext applicationContext;@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {Class<?> clazz = bean.getClass();Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {RateLimit annotation = AnnotationUtils.findAnnotation(method, RateLimit.class);if (annotation != null) {int limit = annotation.limit();int timeout = annotation.timeout();String key = "rate_limiter:" + clazz.getName() + ":" + method.getName() + ":" +Arrays.toString(method.getParameterTypes());RedisTemplate<String, String> redisTemplate = applicationContext.getBean(RedisTemplate.class);RateLimiterInterceptor rateLimiterInterceptor = new RateLimiterInterceptor(redisTemplate, key, limit, timeout);this.rateLimiterMap.put(method, key);WebMvcConfigurer appConfig = (WebMvcConfigurer) applicationContext.getBean(WebMvcConfigurer.class);appConfig.addInterceptors(rateLimiterInterceptor);}}return bean;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

上述代码中,我们通过注解扫描所有带有@RateLimit注解的方法,并在应用程序启动时生成对应的拦截器和key。这里使用了RedisTemplate将key与计数器存储到Redis中。

接下来,创建一个自定义拦截器类RateLimiterInterceptor,并在preHandle方法中添加接口防刷逻辑。其中,根据之前生成的key从Redis中获取对应的计数器并进行限制。例如:

public class RateLimiterInterceptor implements HandlerInterceptor {private final RedisTemplate<String, String> redisTemplate;private final String key;private final int limit;private final int timeout;public RateLimiterInterceptor(RedisTemplate<String, String> redisTemplate, String key, int limit, int timeout) {this.redisTemplate = redisTemplate;this.key = key;this.limit = limit;this.timeout = timeout;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String ip = request.getRemoteAddr();String realKey = key + ":" + ip;Long count = redisTemplate.opsForValue().increment(realKey, 1);redisTemplate.expire(realKey, timeout, TimeUnit.SECONDS);if (count > limit) {response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());return false;}return true;}
}

最后,在需要限制访问的接口方法上添加@RateLimit注解,例如:

@RestController
public class HelloController {@RateLimit(limit = 5, timeout = 1)@GetMapping("/hello")public String hello() {return "Hello World";}
}

这样,我们就可以实现接口访问防刷功能了。每个IP地址在1秒钟内最多只能发送5个请求。如果超过限制,则返回HTTP 429响应。


http://www.ppmy.cn/news/37035.html

相关文章

丢失了packet.dll原因和解决方法全面指南

packet.dll是Windows操作系统中的一个重要文件&#xff0c;它主要用于网络通信&#xff0c;如果丢失了这个文件&#xff0c;可能会导致网络连接问题。本文将探讨packet.dll文件丢失的原因&#xff0c;并提供相应的解决方法。 一、丢失packet.dll文件的原因 1. 病毒感染&#x…

积性函数及其初级应用

积性函数及其初级应用 垃圾博客&#xff0c;我本地 LaTeX 挂了&#xff0c;艹 大量内容和入门方式都参考了 莫比乌斯反演与数论函数 。感谢 CMD 大爷&#xff01; 0xFF 前置知识 1.质数及其判定&#xff0c;质因数及其分解 小学课本里面讲过质数的定义了&#xff0c;不细讲…

【C++】牛客面试经典题,查找组成一个偶数最接近的两个素数.二进制插入.统计回文.连续最大和.不要二.把字符串转换成整数

目录 1.查找组成一个偶数最接近的两个素数 2.二进制插入 3.strlen和sizeof 4.strcat和strcpy 5.多维数组的解引用 6. 统计回文 7. 连续最大和 8.转义字符% 9.不要二 10.把字符串转换成整数 1.查找组成一个偶数最接近的两个素数 观察这个题目的要求&#xff0c;我们…

华为OD机试【密室逃生游戏】

密室逃生游戏 题目 小强增在参加《密室逃生》游戏&#xff0c;当前关卡要求找到符合给定 密码 K&#xff08;升序的不重复小写字母组 成&#xff09; 的箱子&#xff0c; 并给出箱子编号&#xff0c;箱子编号为 1~N 。 每个箱子中都有一个 字符串 s &#xff0c;字符串由大写字…

用Graphviz在线绘制有限状态机等结构化的图

1.打开Graphviz的官网 官网链接&#xff1a;Graphviz 官网里有很多示例&#xff0c;有各种各样的图&#xff0c;可以根据个人需要选择。 2.点击某个示例&#xff0c;进入详情 这个页面能够看到绘制该图的dot代码。 3.进入编辑页面 点击该页面的Edit in Playground按钮&am…

2022蓝桥杯省赛——修剪灌木

问题描述 爱丽丝要完成一项修剪灌木的工作。 有 N 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晩会修剪一棵灌木, 让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始, 每天向右修剪一棵灌木。当修剪了最右侧的灌木后, 她会调转方向, 下一天开始向左修剪…

Python(白银时代)——文件操作

文件的基本操作 概念 在计算机中&#xff0c;文件是以 二进制 的方式保存在磁盘上的 文本文件 和 二进制文件 文本文件&#xff08;用记事本打开能直接能看懂的&#xff09; 可以使用 文本编辑软件查看 本质上还是二进制的,比如 Python的源码文件 二进制文件&#xff08;用…

四福来轮全向底盘实现画图功能

1. 功能说明 本文示例将实现四轮全向底盘绘制正六边形的功能。 2. 结构说明 全向底盘具备结构简单、运动灵活等特点。四轮全向底盘采用全向福来轮作为执行轮&#xff0c;四个轮成正方形分布&#xff0c;且每个轮在斜45方向安装。全向福来轮由主轮和副轮组成&#xff0c;主轮和副…