package com.nova.sankuai.infra.utils;
|
|
import com.nova.sankuai.domain.vo.common.MessageCode;
|
import com.nova.sankuai.domain.vo.common.MessageImageCode;
|
import com.nova.sankuai.domain.vo.common.MessageVerifyVo;
|
import com.nova.sankuai.infra.config.CommonException;
|
import org.apache.commons.lang3.StringUtils;
|
import org.slf4j.Logger;
|
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpStatus;
|
import org.springframework.http.ResponseEntity;
|
|
import java.awt.image.BufferedImage;
|
import java.io.IOException;
|
import java.util.HashMap;
|
import java.util.Map;
|
import java.util.Random;
|
import java.util.regex.Pattern;
|
|
import static cn.hutool.core.util.ReUtil.isMatch;
|
|
/**
|
* @author weikangdi
|
*/
|
public class MessageCodeUtil {
|
|
public static Map<String, MessageCode> CODE_LIST = new HashMap<>();
|
|
public static Map<String, MessageImageCode> IMAGE_CODE_LIST = new HashMap<>();
|
|
public static Map<String, MessageVerifyVo> PHONE_VERIFY_LIST = new HashMap<>();
|
|
public static Map<String, MessageVerifyVo> IP_VERIFY_LIST = new HashMap<>();
|
|
public static final int COUNT_LIMIT = 30;
|
|
public static final long EXPIRED_TIME = 300000L;
|
public static final long INTERVAL_TIME = 90000L;
|
|
private static final String REGEX_MOBILE_EXACT = "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$";
|
private static final Pattern PATTERN_REGEX_MOBILE_EXACT = Pattern.compile(REGEX_MOBILE_EXACT);
|
|
|
public static MessageCode getCode(String phone) {
|
return CODE_LIST.get(phone);
|
}
|
|
public static void setCode(String phone, MessageCode code) {
|
if (CODE_LIST.get(phone) == null) {
|
CODE_LIST.put(phone, code);
|
} else {
|
CODE_LIST.replace(phone, code);
|
}
|
}
|
|
public static void checkCode(String phone, String code) {
|
MessageCode messageCode = MessageCodeUtil.getCode(phone);
|
if (messageCode == null) {
|
throw new CommonException("无效的验证码");
|
}
|
if (messageCode.getCreateTime() != null && messageCode.getCreateTime() < (System.currentTimeMillis() - EXPIRED_TIME)) {
|
throw new CommonException("验证码已过期");
|
}
|
if (!code.equals(messageCode.getCode())) {
|
throw new CommonException("验证码错误");
|
}
|
}
|
|
public static MessageCode createCode(String phone) {
|
MessageCode messageCode = null;
|
//随机生成验证码
|
String code = "";
|
Random random = new Random();
|
for (int i = 0; i < 6; i++) {
|
int r = random.nextInt(10);
|
code = code + r;
|
}
|
//生成短信验证码对象
|
messageCode = new MessageCode();
|
messageCode.setPhone(phone);
|
messageCode.setCode(code);
|
messageCode.setCreateTime(System.currentTimeMillis());
|
return messageCode;
|
}
|
|
public static MessageImageCode getImageCode(String phone) {
|
return IMAGE_CODE_LIST.get(phone);
|
}
|
|
public static void setImageCode(String phone, MessageImageCode code) {
|
if (IMAGE_CODE_LIST.get(phone) == null) {
|
IMAGE_CODE_LIST.put(phone, code);
|
} else {
|
IMAGE_CODE_LIST.replace(phone, code);
|
}
|
}
|
|
|
public static MessageVerifyVo getPhoneVerify(String phone) {
|
return PHONE_VERIFY_LIST.get(phone);
|
}
|
|
public static void setPhoneVerify(String phone, String ip) {
|
MessageVerifyVo messageVerifyVo = PHONE_VERIFY_LIST.get(phone);
|
if (messageVerifyVo == null) {
|
messageVerifyVo = new MessageVerifyVo();
|
messageVerifyVo.setPhone(phone);
|
messageVerifyVo.setCount(1);
|
messageVerifyVo.setIp(ip);
|
messageVerifyVo.setLastApplyTime(System.currentTimeMillis());
|
PHONE_VERIFY_LIST.put(phone, messageVerifyVo);
|
} else {
|
messageVerifyVo.setCount(messageVerifyVo.getCount() + 1);
|
messageVerifyVo.setLastApplyTime(System.currentTimeMillis());
|
PHONE_VERIFY_LIST.replace(phone, messageVerifyVo);
|
}
|
}
|
|
public static MessageVerifyVo getIpVerify(String ip) {
|
return IP_VERIFY_LIST.get(ip);
|
}
|
|
public static void setIpVerify(String phone, String ip) {
|
MessageVerifyVo messageVerifyVo = IP_VERIFY_LIST.get(ip);
|
if (messageVerifyVo == null) {
|
messageVerifyVo = new MessageVerifyVo();
|
messageVerifyVo.setPhone(phone);
|
messageVerifyVo.setCount(1);
|
messageVerifyVo.setIp(ip);
|
messageVerifyVo.setLastApplyTime(System.currentTimeMillis());
|
IP_VERIFY_LIST.put(ip, messageVerifyVo);
|
} else {
|
messageVerifyVo.setCount(messageVerifyVo.getCount() + 1);
|
messageVerifyVo.setLastApplyTime(System.currentTimeMillis());
|
IP_VERIFY_LIST.replace(ip, messageVerifyVo);
|
}
|
}
|
|
public static boolean sendVerify(String phone, String ip, Logger logger) {
|
MessageCode code = getCode(phone);
|
MessageVerifyVo ipVerify = getIpVerify(ip);
|
MessageVerifyVo phoneVerify = getPhoneVerify(phone);
|
if (phoneVerify != null) {
|
Long lastApplyTime = phoneVerify.getLastApplyTime() + INTERVAL_TIME;
|
if (System.currentTimeMillis() < lastApplyTime) {
|
logger.error("登录验证码错误日志: 该手机号在验证码有效期内重复发送验证码,用户手机:" + phone + " 用户IP:" + ip);
|
return false;
|
}
|
if (phoneVerify.getCount() >= COUNT_LIMIT) {
|
logger.error("登录验证码错误日志: 该手机号已达到每日上限,用户手机:" + phone + " 用户IP:" + ip);
|
return false;
|
}
|
}
|
if (ipVerify != null) {
|
Long lastApplyTime = ipVerify.getLastApplyTime() + INTERVAL_TIME;
|
if (System.currentTimeMillis() < lastApplyTime) {
|
logger.error("登录验证码错误日志: 该IP在验证码有效期内重复发送验证码,用户手机:" + phone + " 用户IP:" + ip);
|
return false;
|
}
|
}
|
if (code != null) {
|
long time = code.getCreateTime() + INTERVAL_TIME;
|
if (System.currentTimeMillis() < time) {
|
logger.error("登录验证码错误日志: 验证期内重复发送验证码,用户手机:" + phone + " 用户IP:" + ip);
|
return false;
|
}
|
}
|
return true;
|
}
|
|
public static boolean verifyPhone(String phone) {
|
if (!isMatch(PATTERN_REGEX_MOBILE_EXACT, phone)) {
|
return false;
|
}
|
return true;
|
}
|
|
public static ResponseEntity getGenerateImgCode(String phone) throws IOException {
|
ImageVerifyCode vCode = new ImageVerifyCode();
|
BufferedImage image = vCode.getImage();
|
String img = ImageVerifyCode.image2Base64(image);
|
String verifyCode = vCode.getEncodedText();
|
HashMap<String, Object> body = new HashMap<>();
|
body.put("verifyCode", verifyCode);
|
MessageCode code = MessageCodeUtil.getCode(phone);
|
if (code == null) {
|
body.put("isShow", false);
|
} else {
|
body.put("isShow", true);
|
}
|
body.put("img", img);
|
MessageImageCode messageImageCode = new MessageImageCode(phone, verifyCode, System.currentTimeMillis());
|
setImageCode(phone, messageImageCode);
|
ResultJson<Map<String, Object>> respBody = ResultJson.ok(body);
|
HttpHeaders headers = new HttpHeaders();
|
headers.set("verify-code", verifyCode);
|
return new ResponseEntity<>(respBody, headers, HttpStatus.OK);
|
}
|
|
public static boolean verifyImageCode(String phone, String verifyCode, String inputVerifyCode) {
|
MessageImageCode imageCode = getImageCode(phone);
|
if (imageCode == null) {
|
return false;
|
}
|
IMAGE_CODE_LIST.remove(phone);
|
if (!imageCode.getVerifyCode().equals(verifyCode)) {
|
return false;
|
}
|
if (System.currentTimeMillis() - imageCode.getCreateTime() > 3 * 60 * 1000) {
|
// 验证码超时
|
return false;
|
}
|
if (!StringUtils.equals(verifyCode, ImageVerifyCode.encode(inputVerifyCode))) {
|
// 图形验证码校验失败
|
return false;
|
}
|
return true;
|
}
|
|
public static void clean() {
|
PHONE_VERIFY_LIST = new HashMap<>();
|
IP_VERIFY_LIST = new HashMap<>();
|
}
|
}
|