接口防刷!利用redisson快速实现自定义限流注解

问题:
在日常开发中,一些重要的对外接口,需要加上访问频率限制,以免造成资��损失。

如登录接口,当用户使用手机号+验证码登录时,一般我们会生成6位数的随机验证码,并将验证码有效期设置为1-3分钟,如果对登录接口不加以限制,理论上,通过技术手段,快速重试100000次,即可将验证码穷举出来。

解决思路:对登录接口加上限流操作,如限制一分钟内最多登录5次,登录次数过多,就返回失败提示,或者将账号锁定一段时间。

实现手段:利用redis的有序集合即Sorted Set数据结构,构造一个令牌桶来实施限流。而redisson已经帮我们封装成了RRateLimiter,通过redisson,即可快速实现我们的目标。

  • 定义一个限流注解

      import org.redisson.api.RateIntervalUnit;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface GlobalRateLimiter {String key();long rate();long rateInterval() default 1L;RateIntervalUnit rateIntervalUnit() default RateIntervalUnit.SECONDS;}
    
  • 利用aop进行切面

      import com.zj.demoshow.annotion.GlobalRateLimiter;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.redisson.Redisson;import org.redisson.api.RRateLimiter;import org.redisson.api.RateIntervalUnit;import org.redisson.api.RateType;import org.springframework.beans.factory.annotation.Value;import org.springframework.core.DefaultParameterNameDiscoverer;import org.springframework.expression.Expression;import org.springframework.expression.ExpressionParser;import org.springframework.expression.spel.standard.SpelExpressionParser;import org.springframework.expression.spel.support.StandardEvaluationContext;import org.springframework.stereotype.Component;import javax.annotation.Resource;import java.lang.reflect.Method;import java.util.concurrent.TimeUnit;@Aspect@Component@Slf4jpublic class GlobalRateLimiterAspect {@Resourceprivate Redisson redisson;@Value("${spring.application.name}")private String applicationName;private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();@Pointcut(value = "@annotation(com.zj.demoshow.annotion.GlobalRateLimiter)")public void cut() {}@Around(value = "cut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();Method method = methodSignature.getMethod();String className = method.getDeclaringClass().getName();String methodName = method.getName();GlobalRateLimiter globalRateLimiter = method.getDeclaredAnnotation(GlobalRateLimiter.class);Object[] params = joinPoint.getArgs();long rate = globalRateLimiter.rate();String key = globalRateLimiter.key();long rateInterval = globalRateLimiter.rateInterval();RateIntervalUnit rateIntervalUnit = globalRateLimiter.rateIntervalUnit();if (key.contains("#")) {ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext ctx = new StandardEvaluationContext();String[] parameterNames = discoverer.getParameterNames(method);if (parameterNames != null) {for (int i = 0; i < parameterNames.length; i++) {ctx.setVariable(parameterNames[i], params[i]);}}Expression expression = parser.parseExpression(key);Object value = expression.getValue(ctx);if (value == null) {throw new RuntimeException("key无效");}key = value.toString();}key = applicationName + "_" + className + "_" + methodName + "_" + key;log.info("设置限流锁key={}", key);RRateLimiter rateLimiter = this.redisson.getRateLimiter(key);if (!rateLimiter.isExists()) {log.info("设置流量,rate={},rateInterval={},rateIntervalUnit={}", rate, rateInterval, rateIntervalUnit);rateLimiter.trySetRate(RateType.OVERALL, rate, rateInterval, rateIntervalUnit);//设置一个过期时间,避免key一直存在浪费内存,这里设置为延长5分钟long millis = rateIntervalUnit.toMillis(rateInterval);this.redisson.getBucket(key).expire(Long.sum(5 * 1000 * 60, millis), TimeUnit.MILLISECONDS);}boolean acquire = rateLimiter.tryAcquire(1);if (!acquire) {//这里直接抛出了异常  也可以抛出自定义异常,通过全局异常处理器拦截进行一些其他逻辑的处理throw new RuntimeException("请求频率过高,此操作已被限制");}return joinPoint.proceed();}}
    

ok,通过以上两步,即可完成我们的限流注解了,下面通过一个接口验证下效果。

新建一个controller,写一个模拟登录的方法。

@RestController
@RequestMapping(value = "/user")
public class UserController {@PostMapping(value = "/testForLogin")//以account为锁的key,限制每分钟最多登录5次@GlobalRateLimiter(key = "#params.account", rate = 5, rateInterval = 60)R<Object> testForLogin(@RequestBody @Validated LoginParams params) {//登录逻辑return R.success("登录成功");}
}

启动服务,通过postman访问此接口进行验证。
image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/47728.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【iOS】——编译链接和动态链接器

前言 计算机语言分为机器语言&#xff1a;汇编语言&#xff0c;高级语言。 可以将高级语言分为两种&#xff1a;1&#xff0c;编译语言和解释型语言&#xff08;直译式语言&#xff09;。 编译型语言&#xff08;一次性翻译&#xff09; 编译型语言的程序只要经过编译器编译之…

Android 大屏外接显示器锁屏无触摸

一、大海捞针 1、首先查看log,发现异常log log表示主显示器即id 0的显示器有可交互窗口但是没有焦点,副显示器即id 4有焦点但是没有可交互窗口。猜想副显示器把主显示器的焦点抢走了,只需把焦点从副显示器挪回主显示器即可。 通过查看源代码知道上面这段log来自于InputDi…

filebeat,kafka,clickhouse,ClickVisual搭建轻量级日志平台

springboot集成链路追踪 springboot版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.3</version><relativePath/> <!-- lookup parent from…

【CSS in Depth 2 精译_019】3.2 CSS 的盒模型

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

【Qt安装与简易串口控制Arduino开发板小灯教程】

【Qt安装与简易串口控制Arduino开发板小灯教程】 1. 前言2. QT环境搭建3. 验证QT_Creator是否安装成功3.1 设计流程3. 2 上位机界面设计 4. 上位机逻辑代码编写4.1 添加串口库、包含串口相关头文件4.2 添加QSerialPort成员4.3 创建串口对象、搜索所有可用串口4.4 在编写“打开串…

微软成为PostgreSQL主要贡献者

微软对PostgreSQL贡献的很多新功能都来自于客户在使用微软Azure上的PostgreSQL管理实例数据库&#xff0c;所以这些新功能都来自于真实的客户需求 微软贡献的这些新功能都是比较实用的功能 在这里&#xff0c;【真实的客户需求】要突出一下&#xff0c;因为现在很多社区贡献者…

4. docker镜像、Dockerfile

docker镜像、Dockerfile 一、docker镜像1、镜像介绍2、镜像核心技术 二、Dockerfile定制镜像1、Dockerfile使用流程1.1 编写Dockerfile1.2、构建镜像1.3 创建容器测试镜像定制操作 2、Dockerfile常用指令 一、docker镜像 1、镜像介绍 分层的文件系统 优势&#xff1a;节省空间…

基于JAVA+SpringBoot+uniapp的心理小程序(小程序版本)

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、SpringCloud、Layui、Echarts图表、Nodejs、爬…

docker默认存储地址 var/lib/docker 满了,换个存储地址操作流程

1. 查看docker 存储地址 docker info如下 var/lib/docker2、查看内存大小 按需执行 df -h 找超过100M的大文件 find / -type f -size 100M -exec ls -lh {} \; df -Th /var/lib/docker 查找这个文件的容量 df -h 查找所有挂载点 du -hs /home/syy_temp/*1、df -h 2、sud…

2-38 基于matlab的蚁群算法优化无人机uav巡检

基于matlab的蚁群算法优化无人机uav巡检&#xff0c;巡检位置坐标可根据需求设置&#xff0c;从基地出发&#xff0c;返回基地&#xff0c;使得路径最小。可设置蚁群数量&#xff0c;信息素系数。输出最佳路线长度。程序已调通&#xff0c;可直接运行。 2-38 蚁群算法优化无人…

科普文:多线程如何使用CPU缓存?

一、前言 计算机的基础知识聊的比较少&#xff0c;但想要更好的理解多线程以及为后续多线程的介绍做铺垫&#xff0c;所以有必要单独开一篇来聊一下 CPU cache。 二、CPU 前面有一篇文章关于 CPU是如何进行计算 感兴趣的同学&#xff0c;可以先移步了解一下&#xff0c;不了…

[003-02-10].第10节:Docker环境下搭建Redis主从复制架构

我的博客大纲 我的后端学习大纲 我的Redis学习大纲 1.cluster&#xff08;集群&#xff09;模式-docker版 哈希槽分区进行亿级数据存储 1.1.面试题&#xff1a;1~2亿条数据需要缓存&#xff0c;请问如何设计这个存储案例 1.回答&#xff1a;单机单台100%不可能&#xff0c;肯…

细说MCU用定时器控制ADC采样频率的实现方法并通过Simulink查看串口输出波形

目录 一、硬件工程 二、建立Simulink模型 1.安装MATLAB和Simulink 2.建立Simulink模型 三、代码修改 1.修改回调函数 2.产看结果 3.完整的main.c 本文作者的文章 细说MCU用定时器控制ADC采样频率的实现方法-CSDN博客 https://wenchm.blog.csdn.net/article/details/…

270-VC709E 基于FMC接口的Virtex7 XC7VX690T PCIeX8 接口卡

一、板卡概述 本板卡基于Xilinx公司的FPGA XC7VX690T-FFG1761 芯片&#xff0c;支持PCIeX8、两组 64bit DDR3容量8GByte&#xff0c;HPC的FMC连接器&#xff0c;板卡支持各种FMC子卡扩展。软件支持windows&#xff0c;Linux操作系统。 二、功能和技术指标&#xff1a; 板卡功…

Getx学习笔记之中间件鉴权

目录 前言 一、实现步骤 1.添加依赖 2.创建鉴权中间件 3.定义路由 4.设置初始路由 5.模拟登陆状态 二、Getx鉴权步骤总结 三、本文demo示例 四、参考文章 前言 在 Flutter 中&#xff0c;使用 GetX 可以很方便地实现中间件鉴权&#xff08;Authentication&#xff09…

MySQL生产环境迁移至YashanDB数据库深度体验

前言 首届YashanDB「迁移体验官」开放后&#xff0c;陆续收到「体验官」们的投稿&#xff0c;小崖在此把优秀的投稿文章分享给大家~今天分享的用户文章是《MySQL生产环境迁移至YashanDB数据库深度体验》&#xff08;作者&#xff1a;呆呆的私房菜&#xff09;&#xff0c;满满…

Python简化命令行界面库之fire使用详解

概要 在开发命令行工具时,开发者通常需要编写大量代码来解析命令行参数,这既耗时又容易出错。Python Fire 是 Google 开源的一个库,旨在简化命令行界面的开发。它可以将任何 Python 对象自动生成一个命令行界面,从而大大减少了开发时间和代码复杂度。本文将详细介绍 Pytho…

Elasticsearch基础(五):使用Kibana Discover探索数据

文章目录 使用Kibana Discover探索数据 一、添加样例数据 二、数据筛选 使用Kibana Discover探索数据 一、添加样例数据 登录Kibana。在Kibana主页的通过添加集成开始使用区域&#xff0c;单击试用样例数据。 在更多添加数据的方式页面下方&#xff0c;单击其他样例数据集…

Vscode+Pyside6开发之虚拟环境配置以及错误解决

Pyside开发之虚拟环境配置以及错误解决 开发环境一、项目创建以及虚拟环境设置1.创建项目2. 新建py文件,新建虚拟环境3.激活虚拟环境二、项目位置改变pip命令报错1.删除原来的虚拟环境2. 产生包列表文件requirements.txt3.重新创建虚拟环境4.重新安装包文件5.其他错误开发环境…

Notepad++换安装路径之后,右键打开方式报错:Windows无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目。的处理方法

把Notepad添加到右键打开方式&#xff0c;可以参考下面的3篇文章添加&#xff1a; https://blog.csdn.net/xiaoerbuyu1233/article/details/88287747 https://blog.csdn.net/qq_44000337/article/details/120277317 https://www.cnblogs.com/zhrngM/p/12899026.html 这里主要是…