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

【NFTurbo】基于Redisson滑动窗口实现验证码发送限流

【NFTurbo】基于Redisson滑动窗口实现验证码发送限流

  • 1. 场景
  • 2. 代码

1. 场景

服务在登录和注册的时候需要短信验证,为了防止被灰黑产抓包盗刷,需要限制次数,这里我们在前端做了按钮的置灰,但是后端接口还是要做防控的。

2. 代码

@GetMapping("/sendCaptcha")
public Result<Boolean> sendCaptcha(@IsMobile String telephone) {NoticeResponse noticeResponse = noticeFacadeService.generateAndSendSmsCaptcha(telephone);return Result.success(noticeResponse.getSuccess());
}
package cn.hollis.nft.turbo.notice.facade;import cn.hollis.nft.turbo.api.notice.response.NoticeResponse;
import cn.hollis.nft.turbo.api.notice.service.NoticeFacadeService;
import cn.hollis.nft.turbo.base.exception.SystemException;
import cn.hollis.nft.turbo.limiter.SlidingWindowRateLimiter;
import cn.hollis.nft.turbo.notice.domain.constant.NoticeState;
import cn.hollis.nft.turbo.notice.domain.entity.Notice;
import cn.hollis.nft.turbo.notice.domain.service.NoticeService;
import cn.hollis.nft.turbo.rpc.facade.Facade;
import cn.hollis.nft.turbo.sms.SmsService;
import cn.hollis.nft.turbo.sms.response.SmsSendResponse;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;import java.util.Date;
import java.util.concurrent.TimeUnit;import static cn.hollis.nft.turbo.api.notice.constant.NoticeConstant.CAPTCHA_KEY_PREFIX;
import static cn.hollis.nft.turbo.base.exception.BizErrorCode.SEND_NOTICE_DUPLICATED;/*** @author Hollis*/
@DubboService(version = "1.0.0")
public class NoticeFacadeServiceImpl implements NoticeFacadeService {@Autowiredprivate SlidingWindowRateLimiter slidingWindowRateLimiter;@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate NoticeService noticeService;@Autowiredprivate SmsService smsService;/*** 生成并发送短信验证码** @param telephone 接收验证码的手机号码* @return 验证码发送结果响应对象*/@Facade@Overridepublic NoticeResponse generateAndSendSmsCaptcha(String telephone) {// 使用滑动窗口限流器控制验证码发送频率,每个手机号60秒内只能发送1次Boolean access = slidingWindowRateLimiter.tryAcquire(telephone, 1, 60);if (!access) {throw new SystemException(SEND_NOTICE_DUPLICATED);}// 生成4位随机数字验证码String captcha = RandomUtil.randomNumbers(4);// 将验证码存储到Redis中,设置5分钟过期时间redisTemplate.opsForValue().set(CAPTCHA_KEY_PREFIX + telephone, captcha, 5, TimeUnit.MINUTES);Notice notice = noticeService.saveCaptcha(telephone, captcha);// 异步发送短信验证码Thread.ofVirtual().start(() -> {SmsSendResponse result = smsService.sendMsg(notice.getTargetAddress(), notice.getNoticeContent());if (result.getSuccess()) {notice.setState(NoticeState.SUCCESS);notice.setSendSuccessTime(new Date());noticeService.updateById(notice);} else {notice.setState(NoticeState.FAILED);notice.addExtendInfo("executeResult", JSON.toJSONString(result));noticeService.updateById(notice);}});return new NoticeResponse.Builder().setSuccess(true).build();}
}
package cn.hollis.nft.turbo.limiter;import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;/*** 滑动窗口限流服务** @author Hollis*/
public class SlidingWindowRateLimiter implements RateLimiter {private RedissonClient redissonClient;private static final String LIMIT_KEY_PREFIX = "nft:turbo:limit:";public SlidingWindowRateLimiter(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@Overridepublic Boolean tryAcquire(String key, int limit, int windowSize) {RRateLimiter rRateLimiter = redissonClient.getRateLimiter(LIMIT_KEY_PREFIX + key);if (!rRateLimiter.isExists()) {rRateLimiter.trySetRate(RateType.OVERALL, limit, windowSize, RateIntervalUnit.SECONDS);}return rRateLimiter.tryAcquire();}
}
http://www.lryc.cn/news/626349.html

相关文章:

  • CentOS7 离线一键安装 MySQL 8.0
  • SpringBoot前后端token自动续期方案
  • nginx-下载功能-状态统计-访问控制
  • 开源的实时 Web 日志分析器GoAccess安装使用指南
  • 鸿蒙安卓前端中加载丢帧:ArkWeb分析
  • Vue3全局配置Loading的完整指南:从基础到实战
  • electron进程间通信-从主进程到渲染器进程
  • PyTorch API 3 - distributed
  • 实时视频技术选型深度解析:RTSP、RTMP 与 WebRTC 的边界
  • SpringWeb详解
  • Causal-Copilot: An Autonomous Causal Analysis Agent 论文解读
  • Nginx 作为反向代理时设置的请求头
  • 深度解析:RESTful API中的404错误 - 不是所有404都是Bug
  • 安路EF2系列芯片单口ram ip核使用方法
  • 记录 docker容器打包成镜像 在其他服务器快速启动镜像和容器
  • 零基础学Java第二十二讲---异常(2)
  • KV cache
  • 在Excel和WPS表格中制作可打印的九九乘法表
  • MySQL事务及原理详解
  • MySQL 数据与表结构导出 Excel 技术文档
  • 如何使用matlab将目录下不同的excel表合并成一个表
  • python中view把矩阵维度降低的时候是什么一个排序顺序
  • 系统架构设计师备考第1天——系统架构概述
  • 深入Linux内核:架构设计与核心功能解析
  • 车联网(V2X)中万物的重新定义---联网汽车新时代
  • 自动驾驶汽车机器学习安全实用解决方案
  • RK android14 Setting一级菜单IR遥控器无法聚焦问题解决方法
  • Building Systems with the ChatGPT API 使用 ChatGPT API 搭建系统(第二章学习笔记及总结)
  • 汽车ECU实现数据安全存储(机密性保护)的一种方案
  • 【openssl】openssl CA.pl 签发证书操作步骤