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

应用开发2025-11-05 16:01:1249

问题:

在日常开发中,接口解一些重要的防刷对外接口,需要添加访问频率限制,利用流注以免造成资产损失。快速

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

解决思路:

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

实现手段:

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

1. 定义一个限流注解 复制@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalRateLimiter { String key(); long rate(); long rateInterval() default 1L; RateIntervalUnit rateIntervalUnit() default RateIntervalUnit.SECONDS; }1.2.3.4.5.6.7.8.9.10.11.12.13. 2. 利用aop进行切面 复制@Aspect @Component @Slf4j public class GlobalRateLimiterAspect { @Resource private 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(); } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.

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("登录成功"); } }1.2.3.4.5.6.7.8.9.10.11.12.13.

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

可以看到,企商汇在第6次访问接口的时候,抛出了请求限制的异常。

注意点:

设置key的时候,一定要注意唯一性,比如登录接口,可以将登录账号作为唯一性,查询某个人的订单记录时,将用户id作为唯一性,要避免无意义的key,以免误造成全局接口的限流。

设置rateLimiter的rate时,RateType有两种模式:全局 or 客户端,可以根据需求自主设置,一般都使用全局。

b2b供应网
本文地址:http://www.bzuk.cn/html/262f7499663.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

香港CMK的发展与影响(探索CMK模式在香港的实践与前景展望)

加密标准中DES与AES到底是什么?两者有啥区别?

码农和技术大牛的区别就在于是否知道MySQL的这五个私有语句

与网络安全风险作斗争:如何从现在开始

在LINUX中自带的中文输入法 一直不太友好,用的不够爽。最近SOGO开发出了UBUNTU下的SOGO,安装了下。SOGO的智能化  ,是目前用的最舒服的输入法。下面是个人详细的安装步骤以及遇到问题的解决方法。软件名称:搜狗输入法 for Linux 2.0.0.0066 中文官方安装版 32位软件大小:17.8MB更新时间:2015-10-19软件名称:搜狗输入法 for Linux 2.0.0.0066 中文官方安装版 64位软件大小:17.8MB更新时间:2015-10-191、可以使用本文上面提供的下载,也可以打开下图中的SOGO官网,下载搜狗输入法安装包sogou_pinyin_linux_1.1.0.0037_i386.deb ,注意选择32BIT系统的安装包。2、为什么选择32BIT,不选择64BIT的呢?因为我的UBUNTU2.04安装的是32BIT版本。那如何判断系统是32还是64呢?在终端下输入命令getconf LONG_BIT,可以获取当前系统BIT数[xxx@ ~]getconf LONG_BIT323、安装输入法DEB包前,需要升级系统的一些基本库4、执行安装命令[xxx@ ~]sudo dpkg -i sogou_pinyin_linux_1.1.0.0037_i386.deb 发现错误,提示/usr/lib/libfreetype.so.6不是软链接执行以下命令[xxx@ ~]sudo ln -sf /usr/lib/i386-linux-gnu/libfreetype.so.6 /usr/lib/libfreetype.so.6解决后再次执行安装DEB包命令[xxx@ ~]sudo dpkg -i sogou_pinyin_linux_1.1.0.0037_i386.deb这样就可以安装成功5、安装成功后,需要重启电脑,输入法会自动替换成SOGO,测试了下很爽,熟悉的WINDOW回来了,谢谢阅读,希望能帮到大家,请继续关注脚本之家,我们会努力分享更多优秀的文章。相关推荐:Ubuntu 14.10系统中IBUS 中文输入法安装的图文教程

MySQL数据类型隐式转换规则

Revolut遭遇黑客入侵 少量用户数据被暴露

PostgreSQL之时间戳自动更新

热门文章

友情链接

滇ICP备2023006006号-33