短信验证码防刷

常规手段

  • 前端加一分钟倒计时(光加这个解决不了问题,可以抓包直接绕过去)
  • 校验码(人机互动)
  • 后端加时间,一分钟内准重新发送
  • 后端加10分钟内验证码过期
  • 一个手机一天内限制发送次数(这个一般短信云厂商会提供)

实现流程图

未命名文件 (1).png

代码实现

核心 pom介绍

图形验证码

        
        
            com.baomidou
            kaptcha-spring-boot-starter
            1.1.0
        

存储使用的是redis

       
            org.springframework.boot
            spring-boot-starter-data-redis
            
                
                    io.lettuce
                    lettuce-core
                
            
        
        
        
            redis.clients
            jedis
        

实现代码

图形验证码

@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("");
  }

全部代码地址

https://gitee.com/ethanlab/simple/tree/master/simple-sms

你可能感兴趣的:(短信验证码防刷)