需求:一定时间内禁止重复发送邮件
方式一:前端增加校验倒计时,不到60秒按钮不给点击
简单
不安全,存在绕过的情况
方式二:增加Redis存储,发送的时候设置下额外的key,并且60秒后过期
非原子操作,存在不一致性
增加的额外的key - value存储,浪费空间
/**
* 前置:判断是否重复发送
*
* 1、存储验证码到缓存
*
* 2、发送邮箱验证码
*
* 后置:存储发送记录
**/
方式三:基于原先的key拼装时间戳 (推荐使用)
好处:满足了当前节点内的原子性,也满足业务需求
注册邮箱验证码防刷落地和整体测试
public JsonData sendCode(SendCodeEnum sendCodeEnum, String to) {
String cacheKey = String.format(CacheKey.CHECK_CODE_KEY,sendCodeEnum.name(),to);
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
//如果不为空,则判断是否60秒内重复发送
if(StringUtils.isNotBlank(cacheValue)){
long ttl = Long.parseLong(cacheValue.split("_")[1]);
//当前时间戳-验证码发送时间戳,如果小于60秒,则不给重复发送
if(CommonUtil.getCurrentTimestamp() - ttl < 1000*60){
log.info("重复发送验证码,时间间隔:{} 秒",(CommonUtil.getCurrentTimestamp()-ttl)/1000);
return JsonData.buildResult(BizCodeEnum.CODE_LIMITED);
}
}
//拼接验证码 2322_324243232424324
String code = CommonUtil.getRandomCode(6);
String value = code+"_"+CommonUtil.getCurrentTimestamp();
redisTemplate.opsForValue().set(cacheKey,value,CODE_EXPIRED,TimeUnit.MILLISECONDS);
if(CheckUtil.isEmail(to)){
//邮箱验证码
mailService.sendMail(to,SUBJECT,String.format(CONTENT,code));
return JsonData.buildSuccess();
} else if(CheckUtil.isPhone(to)){
//短信验证码
}
return JsonData.buildResult(BizCodeEnum.CODE_TO_ERROR);
}