常规手段
- 前端加一分钟倒计时(光加这个解决不了问题,可以抓包直接绕过去)
- 校验码(人机互动)
- 后端加时间,一分钟内准重新发送
- 后端加10分钟内验证码过期
- 一个手机一天内限制发送次数(这个一般短信云厂商会提供)
实现流程图
未命名文件 (1).png代码实现
核心 pom介绍
图形验证码
<!--图形验证码 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>kaptcha-spring-boot-starter</artifactId>
<version>1.1.0</version>
</dependency>
存储使用的是redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--客户端使用 jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
实现代码
图形验证码
@GetMapping("kaptcha")
public void kaptcha(HttpServletRequest request, HttpServletResponse response){
String captchaText = captchaProducer.createText();
log.info("验证码内容:{}",captchaText);
//存储redis,配置过期时间,3分钟图形验证码过期
redisTemplate.opsForValue().set(getCaptchaKey(request),captchaText,60*1000*3, TimeUnit.MILLISECONDS);
BufferedImage bufferedImage = captchaProducer.createImage(captchaText);
try (ServletOutputStream outputStream = response.getOutputStream()){
ImageIO.write(bufferedImage,"jpg",outputStream);
outputStream.flush();
} catch (IOException e) {
log.error("获取流出错:{}",e.getMessage());
}
return;
}
/**
* 根据浏览器明细获取key
*
* @param request
* @return
*/
private String getCaptchaKey(HttpServletRequest request) {
String ip = CommonUtil.getIpAddress(request);
String userAgent = request.getHeader("User-Agent");
String key = "sms-service:captcha:" + CommonUtil.MD5(ip + userAgent);
log.info("图形验证码key:{}", key);
return key;
}
短信部分核心代码
@PostMapping("send_code")
public R send(HttpServletRequest request, @RequestBody SmsReq smsReq){
String key = getCaptchaKey(request);
String cacheCacha = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(cacheCacha)&&cacheCacha.equalsIgnoreCase(smsReq.getCatcha())){
redisTemplate.delete(key);
return sendService.send(smsReq.getTel());
}else{
return R.error(-1,"图形验证码错误");
}
}
@Override
public R send(String to) {
String cacheKey =String.format(Constant.SMS_LOGIN_KEY,to);
String cacheCode = redisTemplate.opsForValue().get(cacheKey);
if (cacheCode!=null&&!StringUtils.isNotBlank(cacheCode)){
String ttl = cacheCode.split("_")[1];
Long time = System.currentTimeMillis()-Long.parseLong(ttl);
if (time>60*1000){
return R.error(2,"请稍后再发");
}
}
//这里默认验证码为6666
String code = "6666";
String codeValue = code+"_"+System.currentTimeMillis();
//模拟发送短信
smsComponent.send(to,code);
//验证码有效期10分钟有效
redisTemplate.opsForValue().set(cacheKey,codeValue,10*60*1000, TimeUnit.MILLISECONDS);
return R.success("");
}
网友评论