当前位置: 首页 > news >正文

使用Spring Boot自定义注解 + AOP实现基于IP的接口限流和黑白名单

在这里插入图片描述

😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》本专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
💕《Jenkins实战》专栏主要介绍Jenkins+Docker+Git+Maven的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

使用 Spring Boot 自定义注解和AOP实现基于IP的接口限流和黑白名单

  • 前言
  • 项目初始化
  • 自定义限流注解
  • 编写限流切面
  • Controller中使用限流注解
  • 接口测试
  • 结语

前言

在我们日常开发的项目中为了保证系统的稳定性,很多时候我们需要对系统做限流处理,它可以有效防止恶意请求对系统造成过载。常见的限流方案主要有:

  • 网关限流NGINXZuul 等 API 网关
  • 服务器端限流:服务端接口限流
  • 令牌桶算法:通过定期生成令牌放入桶中,请求需要消耗令牌才能通过
  • 熔断机制HystrixResilience4j

本文将详细介绍 Spring Boot 通过自定义注解和 AOP(面向切面编程),实现基于 IP 的限流和黑白名单功能,包括如何使用 Redis 存储限流和黑名单信息。

项目初始化

首先,创建一个 Spring Boot 项目,并添加必要的依赖。在 pom.xml 文件中添加以下内容:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
</dependencies>

配置 application.yml 加入 redis 配置

spring:#redisredis:# 地址host: 127.0.0.1# 端口,默认为6379port: 6379

自定义限流注解

创建一个自定义注解 RateLimit

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimit {//限制次数int limit() default 5;//限制时间 秒int timeout() default 60;
}

编写限流切面

使用 AOP 实现限流逻辑,并增加 IP 黑白名单判断 , 使用 Redis 来存储和检查请求次数及黑名单信息。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;@Aspect
@Component
public class RateLimitAspect {@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate HttpServletRequest request;//定义黑名单key前缀private static final String BLACKLIST_KEY_PREFIX = "blacklist:";//定义白名单key前缀private static final String WHITELIST_KEY_PREFIX = "whitelist:";@Around("@annotation(rateLimit)")public Object rateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {//获取IPString ip = request.getRemoteAddr();//黑名单则直接异常if (isBlacklisted(ip)) {throw new RuntimeException("超出访问限制已加入黑名单,1小时后再访问");}//如果是白名单下的不做限制if (isWhitelisted(ip)) {return joinPoint.proceed();}String key = generateKey(joinPoint, ip);int limit = rateLimit.limit();int timeout = rateLimit.timeout();String countStr = redisTemplate.opsForValue().get(key);int count = countStr == null ? 0 : Integer.parseInt(countStr);if (count < limit) {redisTemplate.opsForValue().set(key, String.valueOf(count + 1), timeout, TimeUnit.SECONDS);return joinPoint.proceed();} else {addToBlacklist(ip);throw new RuntimeException("超出请求限制IP已被列入黑名单");}}private boolean isBlacklisted(String ip) {return redisTemplate.hasKey(BLACKLIST_KEY_PREFIX + ip);}private boolean isWhitelisted(String ip) {return redisTemplate.hasKey(WHITELIST_KEY_PREFIX + ip);}private void addToBlacklist(String ip) {redisTemplate.opsForValue().set(BLACKLIST_KEY_PREFIX + ip, "true", 1, TimeUnit.HOURS);}private String generateKey(ProceedingJoinPoint joinPoint, String ip) {String methodName = joinPoint.getSignature().getName();String className = joinPoint.getTarget().getClass().getName();return className + ":" + methodName + ":" + ip;}
}

Controller中使用限流注解

创建一个简单的限流测试Controller,并在需要限流的方法上使用 @RateLimit 注解:,需要编写异常处理,返回RateLimitAspect异常信息,并以字符串形式返回

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api")
public class TestController {//由于是简单的测试项目,这里就直接定义异常处理,并为采用全局异常处理@ExceptionHandler(value = Exception.class)public String handleException(Exception ex) {return ex.getMessage();}@RateLimit(limit = 5, timeout = 60)@GetMapping("/limit")public String testRateLimit() {return "Request successful!";}
}

接口测试

使用接口调试工具,请求接口测试,博主这里使用的是 Apifox,我们60秒内请求5次
前5次均返回 Request successful!
第6次会提示 超出请求限制IP已被列入黑名单

在这里插入图片描述

结语

通过以上步骤,我们成功地使用自定义注解和 AOP 实现了基于 IP 的接口限流和黑白名单功能。这种方法不仅简化了限流逻辑的实现,还增强了系统的安全性和稳定性。小伙伴们可以根据实际需求对限流逻辑进行进一步扩展和优化,例如增加不同的限流策略、动态调整限流参数等。


在这里插入图片描述

相关文章:

  • 【Django】开发个人博客系统【1】
  • 【LeetCode】38.外观数列
  • 第P9周:YOLOv5-Backbone模块实现
  • Leetcode刷题笔记7
  • Java集合【超详细】2 -- Map、可变参数、Collections类
  • 探索Web前端三大主流框架:Angular、React和Vue.js
  • 城市公共交通IC卡消费流程
  • Superset二次开发之更新 SECRET_KEY
  • springboot+vue 社区养老服务系统
  • MySQL中,不能在一个DML(数据操纵语言,如INSERT, UPDATE, DELETE)语句中直接引用目标表进行子查询
  • python 第一天
  • Java----Maven详解
  • Redis常用命令大全
  • 【安装笔记-20240529-Windows-Wireshark 网络协议分析工具】
  • PHP:集成Xunsearch生成前端搜索骨架
  • [PHP内核探索]PHP中的哈希表
  • 【Amaple教程】5. 插件
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • android 一些 utils
  • Computed property XXX was assigned to but it has no setter
  • cookie和session
  • JavaScript创建对象的四种方式
  • leetcode-27. Remove Element
  • Logstash 参考指南(目录)
  • Vue 动态创建 component
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 动态魔术使用DBMS_SQL
  • 猴子数据域名防封接口降低小说被封的风险
  • 驱动程序原理
  • 如何编写一个可升级的智能合约
  • 使用 QuickBI 搭建酷炫可视化分析
  • 赢得Docker挑战最佳实践
  • 正则与JS中的正则
  • Python 之网络式编程
  • ​水经微图Web1.5.0版即将上线
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • #{}和${}的区别是什么 -- java面试
  • (2)MFC+openGL单文档框架glFrame
  • (C++17) optional的使用
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (力扣题库)跳跃游戏II(c++)
  • (详细文档!)javaswing图书管理系统+mysql数据库
  • (转)iOS字体
  • (转)程序员技术练级攻略
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .Net MVC4 上传大文件,并保存表单
  • .NET MVC之AOP
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)