欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

如何在后台实现电子邮件注册 + 验证码 + 防抓取功能

最编程 2024-04-28 13:27:27
...

框架引入,需要引入验证码框架和邮箱服务框架,用Springboot整合所以带有stater,邮箱注册需要防止盗刷,所以需要引入验证码框架,需要防止多次请求,所以选用redis

 <dependency>
     <groupId>com.baomidou</groupId>
     <artifactId>kaptcha-spring-boot-starter</artifactId>
     <version>1.1.0</version>
 </dependency>

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-mail</artifactId>
     <version>2.3.3.RELEASE</version>
</dependency>
 
<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>

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

   jedis性能比RedisTemplate的性能好3倍,并且随着数据量的增大,倍数也成指数增加
因此优先选择jedis,因为他在性能方面完胜RedisTemplate

 邮箱服务配置,通过网易申请申请得到,一些邮箱相关的信息,配置Application文件

spring:
  mail:
    host: smtp.126.com   //发送邮件服务器
    username: xxxx@126.com  //邮箱
    password: xxxxxxx   //客户端授权码 千万注意这个不是密码 是客户端授权码
    from:  xxxx@126.com  //
    properties.mail.smtp.starttls.enable: true
    properties.mail.smtp.starttls.required: true
    properties.mail.smtp.ssl.enable: true  //开启ssl
    default-encoding: utf-8   //编码utf-8
  redis:
host: xxx.xxx.xxx.xxx
port: xxxx
password: xxxx

验证码的配置

@Configuration
public class CaptchaConfig {
    @Bean
    @Qualifier("captchaProducer")
    //重新命名Bean
    public DefaultKaptcha defaultKaptcha(){

        DefaultKaptcha kaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
//        properties.setProperty(Constants.KAPTCHA_BORDER, "yes");
//        properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "220,220,220");
//        //properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "38,29,12");
//        properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "147");
//        properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "34");
//        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "25");
//        //properties.setProperty(Constants.KAPTCHA_SESSION_KEY, "code");
        //验证码个数
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
//        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Courier");
        //字体间隔
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE,"8");
        //干扰线颜色
//        properties.setProperty(Constants.KAPTCHA_NOISE_COLOR, "white");
        //干扰实现类
        properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        //图片样式
        properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple");
        //文字来源
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789");
        Config config = new Config(properties);
        kaptcha.setConfig(config);
        return kaptcha;
    }
}
发送验证码,防止重复请求验证码
  public JsonData sendCode(SendCodeEnum sendCodeEnum, String to) {
        String cacheKey = String.format(CacheKey.CHECK_CODE_KEY,sendCodeEnum.name(),to);
        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
        log.info(cacheValue);
 //二次进入 
if(cacheValue!=null){ long ttl =Long.parseLong(cacheValue.split("_")[1]); if(CommonUtil.getCurrentTimestamp()-ttl<1000*60){ log.info("重复发送验证码,时间间隔为:{}秒",(CommonUtil.getCurrentTimestamp()-ttl)/1000); return JsonData.buildResult(BizCodeEnum.CODE_LIMITED); } } String code = CommonUtil.getRandomCode(6); String value = code +"_" +CommonUtil.getCurrentTimestamp(); redisTemplate.opsForValue().set(cacheKey,value,CODE_EXPIRED, TimeUnit.MILLISECONDS); if(CheckUtils.isEmail(to)){ mailService.sendEmail(to,SUBJECT,String.format(CONTENT,code)); return JsonData.buildSuccess(); }else if(CheckUtils.isPhone(to)) { } return JsonData.buildSuccess(); }

注册功能

 public JsonData register(UserRegisterRequest registerRequest) {
        boolean checkCode= false;
        if( registerRequest.getMail()!=null){
            checkCode = notifyService.checkCode(SendCodeEnum.USER_REGISTER,registerRequest.getMail(),registerRequest.getCode());
        }
        if(!checkCode){
            return JsonData.buildResult(BizCodeEnum.CODE_ERROR);
        }
        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(registerRequest,userDO);
        userDO.setCreateTime(new Date());
        userDO.setSlogan("xxxxx");
        userDO.setSecret("$1$"+ CommonUtil.getRandomCode(8));
        String cryPwd= CommonUtil.MD5(registerRequest.getPwd()+userDO.getSecret());
        userDO.setPwd(cryPwd);
        if(checkUnique(userDO.getMail())){
            int rows =userMapper.insert(userDO);
            log.info("rows={},注册成功:{}",rows,userDO.toString());
            return JsonData.buildSuccess();
        }else{
            return JsonData.buildResult(BizCodeEnum.ACCOUNT_REPEAT);
        }
    } 
controller层
   @Autowired
    private Producer  captchaProducer;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    NotifyService notifyService;
    private  static  final  long CAPTCHA_CODE_EXPIRED= 60*1000*10;
    @GetMapping("captcha")
    public  void getCaptcha(HttpServletRequest request, HttpServletResponse response){
        String captchaText=captchaProducer.createText();
        log.info("图形验证码:{}",captchaText);
        redisTemplate.opsForValue().set(getCaptchaKey(request),captchaText,CAPTCHA_CODE_EXPIRED, TimeUnit.MILLISECONDS);
        BufferedImage bufferedImage = captchaProducer.createImage(captchaText);
        ServletOutputStream outputStream =null;
        try{
            outputStream =response.getOutputStream();
            ImageIO.write(bufferedImage,"jpg",outputStream);
            outputStream.flush();
            outputStream.close();
        }catch (IOException e){
            log.error("获取图形验证码异常{}",e);
        }
    }
    @GetMapping("send_code")
    public JsonData sendRegisterCode(@RequestParam(value="to",required = true) String to, @RequestParam(value = "captcha",required = true) String captcha,HttpServletRequest request){
        String key = getCaptchaKey(request);
        String cacheCaptcha =redisTemplate.opsForValue().get(key);
        log.info("heheee");
        if(captcha!=null &&captcha!=null &&captcha.equalsIgnoreCase(cacheCaptcha)){
            redisTemplate.delete(key);
            JsonData jsonData = notifyService.sendCode(SendCodeEnum.USER_REGISTER,to);
            return jsonData;
        }else{
            return JsonData.buildResult(BizCodeEnum.CODE_TO_ERROR);
        }
    }
    private  String getCaptchaKey(HttpServletRequest request){
        String ip= CommonUtil.getIpAddr(request);
        String userAgent=request.getHeader("User-Agent");
        String key="user-service:captcha"+ip+CommonUtil.MD5(ip+userAgent);
        log.info("ip= {}",ip);
        log.info("userAgent={}",userAgent);
        log.info("key={}",key);
        return key;
    }

邮箱代码编写

@Service
@Slf4j
public class MailServiceImpl implements MailService {

    @Autowired
    JavaMailSender javaMailSender;
    @Value("${spring.mail.from}")
    private  String from;
    @Override
    public void sendEmail(String to,String subject,String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);
        javaMailSender.send(message);
        log.info( "邮箱发送成功 {}",message);
    }
}

后端测试结果

 

 

 

 

 

 

 

 

 总结:redis 首先存储 map<key,value> 首先是 <user-service:captcha:ip+md5(ip+ugent),图形验证码>  然后是map<code:%s:%s,邮箱验证码+当前时间轴> 第一个%s是USER_REGISTER,第二个是要发送的邮箱

代码百度云: 把application文件删除 需要自己配置数据库 redis mail

链接:https://pan.baidu.com/s/1ejwAQ-MnmJGhakXouscXKA
提取码:gcwu
--来自百度网盘超级会员V4的分享

欢迎讨论 +Q3378404370