1.需求:一定时间内禁止重复发送短信
两个时间要求
60秒后才可以重新发送短信验证码
发送的短信验证码10分钟内有效
2.方案
方式一:前端增加校验倒计时,不到60秒按钮不给点击
简单,不安全,存在绕过的情况
方式二:增加Redis存储,发送的时候设置下额外的key,并且60秒后过期
非原子操作,存在不一致性,增加的额外的key - value存储,浪费空间
/**
* 前置:判断是否重复发送
*
* 1、存储验证码到缓存
*
* 2、发送短信验证码
*
* 后置:存储发送记录
**/
方式三:基于原先的key拼装时间戳
好处:满足了当前节点内的原子性,也满足业务需求
3.上代码--使用方式三
public JsonData sendCode(SendCodeEnum sendCodeEnum, String to) {
//拼接key
String cacheKey = String.format(RedisKey.CHECK_CODE_KEY,sendCodeEnum.name(),to);
//根据key,然后从redis中查找是否存在
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
//如果不为空,再判断是否是60秒内重复发送 0122_232131321314132
if(StringUtils.isNotBlank(cacheValue)){
long ttl = Long.parseLong(cacheValue.split("_")[1]);
//当前时间戳-验证码发送的时间戳,如果小于60秒,则不给重复发送
long leftTime = CommonUtil.getCurrentTimestamp() - ttl;
if( leftTime < (1000*60)){
log.info("重复发送短信验证码,时间间隔:{}秒",leftTime);
return JsonData.buildResult(BizCodeEnum.CODE_LIMITED);
}
}
//key不存在redis中,则生成验证码,发送短信
String code = CommonUtil.getRandomCode(6);
//生成拼接好验证码
String value = code+"_"+CommonUtil.getCurrentTimestamp();
redisTemplate.opsForValue().set(cacheKey,value,CODE_EXPIRED,TimeUnit.MILLISECONDS);
if(CheckUtil.isEmail(to)){
//发送邮箱验证码 TODO
}else if(CheckUtil.isPhone(to)){
//发送手机验证码
smsComponent.send(to,smsConfig.getTemplateId(),code);
}
return JsonData.buildSuccess();
}
redis的key value