注册邮箱验证码功能开发

前文提示

开发流程

工具类

public class CommonUtil {
    /**
     * 获取ip
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
           ipAddress = request.getHeader("x-forwarded-for");
           if(ipAddress == null || ipAddress.length() == 0 || "unknow".equalsIgnoreCase(ipAddress)) {
               ipAddress = request.getHeader("Proxy-Client-IP");
           }
           if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
               ipAddress = request.getHeader("WL-Proxy-Client-IP");
           }
           if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
               ipAddress = request.getRemoteAddr();
               if(ipAddress.equals("127.0.0.1")) {
                   // 根据网卡取本机配置的IP
                   InetAddress inet = null;
                   try {
                       inet = InetAddress.getLocalHost();
                   } catch (UnknownHostException e) {
                       e.printStackTrace();
                   }
                   ipAddress = inet.getHostAddress();
               }
           }
           // 对于通过多个代理的情况, 第一个IP为客户端真实IP, 多个IP按照‘,’分割
            if(ipAddress != null && ipAddress.length() > 15) {
                // "***.***.***.***".length() = 15
                if(ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e){
            ipAddress = "";
        }

        return ipAddress;
    }

    /**
     * MD5加密
     * @param data
     * @return
     */
    public static String MD5(String data) {
        try {
            java.security.MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(data.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for(byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }

            return sb.toString().toUpperCase();
        } catch (Exception exception) {

        }

        return null;
    }

    /**
     * 获取验证码随机数
     * @param length
     * @return
     */
    public static String getRandomCode(int length) {
        String sources = "0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for(int j = 0; j < length; j++) {
            sb.append(sources.charAt(random.nextInt(9)));
        }
        return sb.toString();
    }

    /**
     * 获取当前时间戳
     * @return
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }

}

邮箱,手机正则校验

public class CheckUtil {
    
    /**
     * 邮箱正则
     */
    private static final Pattern MAIL_PATTERN = Pattern.compile("^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$");

    /**
     * 手机号正则,暂时未用
     */
    private static final Pattern PHONE_PATTERN = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$");

    /**
     * @param email
     * @return
     */
    public static  boolean isEmail(String email) {
        if (null == email || "".equals(email)) {
            return false;
        }
        Matcher m = MAIL_PATTERN.matcher(email);
        return m.matches();
    }

    /**
     * 暂时未用
     * @param phone
     * @return
     */
    public static boolean isPhone(String phone) {
        if (null == phone || "".equals(phone)) {
            return false;
        }
        Matcher m = PHONE_PATTERN.matcher(phone);
        return m.matches();

    }
}

接口使用的枚举类

public enum SendCodeEnum {

    /**
     * 用户注册
     */
    USER_REGISTER;

}

redis 缓存 key (基于原来的 key 拼装时间戳)

public class CacheKey {

    /**
     * 注册验证码,第一个是类型,第二个是接收号码
     */
    public static final String CHECK_CODE_KEY = "code:%s:%s";

}

Service

public interface NotifyService {

    /**
     * 发送注册码
     * @param sendCodeEnum
     * @param to
     * @return
     */
    JsonData sendCode(SendCodeEnum sendCodeEnum, String to);
}

SerivceImpl

@Service
@Slf4j
public class NotifyServiceImpl implements NotifyService {

    @Autowired
    private MailService mailService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 邮箱验证码有效期10分钟
     */
    private static final long CODE_EXPIRED = 60 * 1000 * 1;

    // 验证码的标题
    private static final String SUBJECT = "1024shop验证码";

    // 验证码内容
    private static final String CONTENT = "您的验证码是%s, 有效时间是60秒。";

    @Override
    public JsonData sendCode(SendCodeEnum sendCodeEnum, String to) {

        String cacheKey = String.format(CacheKey.CHECK_CODE_KEY, sendCodeEnum, to);

        String cacheValue = redisTemplate.opsForValue().get(cacheKey);

        // 如果不为空,则判断是60秒内重复发送
        if(StringUtils.isNotBlank(cacheValue)) {
            long ttl = Long.parseLong(cacheValue.split("_")[1]);
            // 当前时间戳 - 验证码发送时间戳, 如果小于60秒, 则不给重复发送
            if(CommonUtil.getCurrentTimestamp() - ttl < 1000 * 60) {
                log.info("重复发送验证码, 时间间隔:{} 秒", (CommonUtil.getCurrentTimestamp() - ttl) / 1000);
                return JsonData.buildResult(BizCodeEnum.CODE_LIMITED);
            }

        }

        // 拼接验证码 2323_2323232323232323
        String code = CommonUtil.getRandomCode(6);

        String value = code + "_" + CommonUtil.getCurrentTimestamp();

        // 设置超时时间为1分钟
        redisTemplate.opsForValue().set(cacheKey, value, CODE_EXPIRED, TimeUnit.MILLISECONDS);

        // 验证邮箱格式
        if(CheckUtil.isEmail(to)) {
            // 邮箱验证码
            mailService.sendMail(to, SUBJECT, String.format(CONTENT, code));
            return JsonData.buildSuccess();
        } else if(CheckUtil.isPhone(to)) {
            // 短信验证码
        }

        return JsonData.buildResult(BizCodeEnum.CODE_TO_ERROR);
    }
}

Controller

@Api(tags = "通知模块")
@RestController
@RequestMapping("/api/user/v1")
@Slf4j
public class NotifyController {

    @Autowired
    private Producer captchaProducer;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private NotifyService notifyService;

    /**
     * 图形验证码有效期10分钟
     */
    private static final long CAPTCHA_CODE_EXPIRED = 60 * 1000 * 10;

    /**
     * 获取图形验证码
     * @param request
     * @param response
     */
    @ApiOperation("获取图形验证码")
    @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);
        }

    }

    @ApiOperation("发送邮箱注册验证码")
    @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);

        // 校验图形验证码是否一样
        if(captcha != null && cacheCaptcha != null && captcha.equalsIgnoreCase(cacheCaptcha)) {
            // 成功
            redisTemplate.delete(key);
            JsonData jsonData = notifyService.sendCode(SendCodeEnum.USER_REGISTER, to);

            return jsonData;
        } else {
            return JsonData.buildResult(BizCodeEnum.CODE_CAPTCHA_ERROR);
        }

    }


    /**
     * 获取缓存的验证码
     * @param request
     * @return
     */
    private static String getCaptchaKey(HttpServletRequest request) {
        String ip = CommonUtil.getIpAddr(request);

        String userAgent = request.getHeader("User-Agent");

        String key = "user-service:captcha:" + CommonUtil.MD5(ip + userAgent);

        log.info("ip = {}", ip);
        log.info("userAgent = {}", userAgent);
        log.info("key = {}", key);

        return key;
    }

}
posted @ 2022-10-15 11:14  哨音  阅读(293)  评论(0编辑  收藏  举报