安全策略
一小时内只能获取三次,一天内只能获取五次
Redis存储结构
代码展示
import cn.hutool.core.util.RandomUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;@SpringBootTest
public class Test01 {@Resourceprivate StringRedisTemplate stringRedisTemplate;private static final Logger logger = LogManager.getLogger(Test01.class);//redis前缀final String k = "YZM:COUNT:123456";//过期时间final Long EXPIRETIME = 1L;//一小时生成的次数final String HOURCOUNT = "hourCount";//24时生成的次数final String DAYCOUNT = "hourCount";//yzmfinal String YZM = "yzm";//校验一小时内的时间final String TIME = "time";//往Redis中存值public void setYzm(DateTimeFormatter format,Integer hourCountStart,Integer dayCountStart,Boolean sign){logger.info("setYzm |start |往Redis中存值");//验证码的生成时间LocalDateTime now = LocalDateTime.now();//LocalDateTime转StringString date = format.format(now);String yzm = RandomUtil.randomNumbers(6);//发送验证码logger.info("setYzm |····· |验证码:{}",yzm);//准备存储数据HashMap<String, String> yzmInfo = new HashMap<>();if (true==sign){yzmInfo.put("time",date); //验证码生成时间logger.info("setYzm |····· |生成校验时间:{}",date);}yzmInfo.put("hourCount",hourCountStart.toString()); //一小时生成的次数yzmInfo.put("dayCount",dayCountStart.toString()); //24h生成的次数yzmInfo.put("yzm",yzm); //验证码//以hash的结果存入Redis中stringRedisTemplate.opsForHash().putAll(k,yzmInfo);Boolean expire = stringRedisTemplate.expire(k, Duration.ofDays(EXPIRETIME));logger.info("setYzm |end |Redis存储情况:{}",expire);}//获取校验时间,判断是否在一小时内public Boolean getTime(Map<Object, Object> redisMap,DateTimeFormatter format ){logger.info("getTime |start |取校验时间,判断是否在一小时内获取过验证码");String redisTime = redisMap.get(TIME).toString();//String转LocalDatetimeLocalDateTime hourTime = LocalDateTime.parse(redisTime, format);//获取当前时间LocalDateTime now = LocalDateTime.now();//计算时间差,==0 代表一小时内的long betweenHours = ChronoUnit.HOURS.between(hourTime , now );logger.info("getTime |···· |时间差:{}",betweenHours);if (betweenHours==0) {logger.info("getTime |end |结果是true");return true;}logger.info("getTime |end |结果是false");return false;}@Testpublic void getYzmPlus(){Integer hourCountStart = 1; //一小时生成的次数Integer dayCountStart = 1; //24h生成的次数//指定日期格式(格式化日期)DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//查看验证码次数Map<Object, Object> redisMap = stringRedisTemplate.opsForHash().entries(k);logger.info("验证码:{}",redisMap);Boolean sign = true;if (!redisMap.isEmpty()) {logger.info("验证码不为空,代表24h内不是第一次获取验证码");Integer hourCount = Integer.valueOf(redisMap.get(HOURCOUNT).toString());Integer dayCount = Integer.valueOf(redisMap.get(DAYCOUNT).toString());//判断是否一小时内发过验证码Boolean resut = getTime(redisMap, format);if (resut){if (hourCount==3){logger.info("一小时内获取验证码次数上限了!");throw new RuntimeException("一小时内获取验证码次数上限了!");}sign = false;}if (dayCount == 5){logger.info("24时内获取验证码次数上限了!");//返回throw new RuntimeException("24时内获取验证码次数上限了!");}//校验成功,发送验证码并setsetYzm(format,hourCount+=1,dayCount+=1,sign);}else {logger.info("验证码为空,代表24h内第一次获取验证码");//发送验证码并setsetYzm(format,hourCountStart,dayCountStart,sign);}}}