验证码模块完善,增加配置项:
#验证码设置 verification-code: #图形验证码有效时间 秒 包含滑块验证码有效时间, 以及验证通过之后,缓存中存储的验证结果有效时间 effectiveTime: 300 #水印 watermark: LILI-SHOP #干扰项数量 最大2 默认0 interfereNum: 1 #允许误差像素 faultTolerant: 3
This commit is contained in:
parent
f9308fa5bf
commit
ef0eeda469
@ -1,8 +0,0 @@
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.http.multipart.location",
|
||||
"type": "java.lang.String",
|
||||
"description": "Description for spring.http.multipart.location."
|
||||
}
|
||||
] }
|
@ -205,6 +205,16 @@ jasypt:
|
||||
password: lili
|
||||
|
||||
lili:
|
||||
#验证码设置
|
||||
verification-code:
|
||||
#图形验证码有效时间 秒 包含滑块验证码有效时间, 以及验证通过之后,缓存中存储的验证结果有效时间
|
||||
effectiveTime: 300
|
||||
#水印
|
||||
watermark: LILI-SHOP
|
||||
#干扰项数量 最大2 默认0
|
||||
interfereNum: 0
|
||||
#允许误差像素
|
||||
faultTolerant: 3
|
||||
#短信模版配置
|
||||
sms:
|
||||
#登录
|
||||
|
@ -189,9 +189,9 @@ logging:
|
||||
# 输出级别
|
||||
level:
|
||||
cn.lili: info
|
||||
# org.hibernate: debug
|
||||
# org.springframework: debug
|
||||
# org.springframework.data.mongodb.core: debug
|
||||
# org.hibernate: debug
|
||||
# org.springframework: debug
|
||||
# org.springframework.data.mongodb.core: debug
|
||||
file:
|
||||
# 指定路径
|
||||
path: lili-logs
|
||||
@ -204,7 +204,18 @@ jasypt:
|
||||
encryptor:
|
||||
password: lili
|
||||
|
||||
|
||||
lili:
|
||||
#验证码设置
|
||||
verification-code:
|
||||
#图形验证码有效时间 秒 包含滑块验证码有效时间, 以及验证通过之后,缓存中存储的验证结果有效时间
|
||||
effectiveTime: 300
|
||||
#水印
|
||||
watermark: LILI-SHOP
|
||||
#干扰项数量 最大2 默认0
|
||||
interfereNum: 1
|
||||
#允许误差像素
|
||||
faultTolerant: 3
|
||||
#短信模版配置
|
||||
sms:
|
||||
#登录
|
||||
|
@ -0,0 +1,50 @@
|
||||
package cn.lili.common.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 线程配置
|
||||
*
|
||||
* @author Chopper
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "lili.verification-code")
|
||||
public class VerificationCodeProperties {
|
||||
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
* 包含滑块验证码有效时间, 以及验证通过之后,缓存中存储的验证结果有效时间
|
||||
*/
|
||||
private Long effectiveTime = 600L;
|
||||
|
||||
/**
|
||||
* 水印
|
||||
*/
|
||||
private String watermark = "LILI-SHOP";
|
||||
|
||||
/**
|
||||
* 干扰数量 最大数量
|
||||
*/
|
||||
private Integer interfereNum = 0;
|
||||
|
||||
/**
|
||||
* 容错像素
|
||||
*/
|
||||
private Integer faultTolerant = 3;
|
||||
|
||||
|
||||
public String getWatermark() {
|
||||
return watermark;
|
||||
}
|
||||
|
||||
public Integer getInterfereNum() {
|
||||
if (interfereNum > 2) {
|
||||
return 2;
|
||||
}
|
||||
return interfereNum;
|
||||
}
|
||||
}
|
@ -330,7 +330,7 @@ public class CartServiceImpl implements CartService {
|
||||
double totalPrice = tradeDTO.getSkuList().stream().mapToDouble(i -> i.getPurchasePrice() * i.getNum()).sum();
|
||||
if (tradeDTO.getSkuList() != null && !tradeDTO.getSkuList().isEmpty()) {
|
||||
List<String> ids = tradeDTO.getSkuList().parallelStream().filter(i -> Boolean.TRUE.equals(i.getChecked())).map(i -> i.getGoodsSku().getId()).collect(Collectors.toList());
|
||||
List<String> storeIds = new ArrayList<>();
|
||||
|
||||
List<EsGoodsIndex> esGoodsList = esGoodsSearchService.getEsGoodsBySkuIds(ids);
|
||||
for (EsGoodsIndex esGoodsIndex : esGoodsList) {
|
||||
if (esGoodsIndex != null) {
|
||||
@ -341,9 +341,17 @@ public class CartServiceImpl implements CartService {
|
||||
count = currentGoodsCanUse.size();
|
||||
}
|
||||
}
|
||||
storeIds.add(esGoodsIndex.getStoreId());
|
||||
}
|
||||
}
|
||||
|
||||
List<String> storeIds = new ArrayList<>();
|
||||
for (CartSkuVO cartSkuVO : tradeDTO.getSkuList()) {
|
||||
if (!storeIds.contains(cartSkuVO.getStoreId())) {
|
||||
storeIds.add(cartSkuVO.getStoreId());
|
||||
}
|
||||
}
|
||||
|
||||
//获取可操作的优惠券集合
|
||||
List<MemberCoupon> allScopeMemberCoupon = memberCouponService.getAllScopeMemberCoupon(tradeDTO.getMemberId(), storeIds);
|
||||
if (allScopeMemberCoupon != null && !allScopeMemberCoupon.isEmpty()) {
|
||||
//过滤满足消费门槛
|
||||
|
@ -35,6 +35,50 @@ public class ImageUtil {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 干扰图
|
||||
*
|
||||
* @param oriImage 原图
|
||||
* @param templateImage 模板图
|
||||
* @param x 随机扣取坐标X
|
||||
* @param y 随机扣取坐标y
|
||||
*/
|
||||
public static void interfereTemplate(BufferedImage oriImage, BufferedImage templateImage,
|
||||
int x, int y) {
|
||||
//临时数组遍历用于高斯模糊存周边像素值
|
||||
int[][] matrix = new int[3][3];
|
||||
int[] values = new int[9];
|
||||
|
||||
int xLength = templateImage.getWidth();
|
||||
int yLength = templateImage.getHeight();
|
||||
//模板图像宽度
|
||||
for (int i = 0; i < xLength; i++) {
|
||||
//模板图片高度
|
||||
for (int j = 0; j < yLength; j++) {
|
||||
//如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中
|
||||
int rgb = templateImage.getRGB(i, j);
|
||||
if (rgb < 0) {
|
||||
//抠图区域高斯模糊
|
||||
readPixel(oriImage, x + i, y + j, values);
|
||||
fillMatrix(matrix, values);
|
||||
oriImage.setRGB(x + i, y + j, avgMatrix(matrix));
|
||||
}
|
||||
|
||||
//防止数组越界判断
|
||||
if (i == (xLength - 1) || j == (yLength - 1)) {
|
||||
continue;
|
||||
}
|
||||
int rightRgb = templateImage.getRGB(i + 1, j);
|
||||
int downRgb = templateImage.getRGB(i, j + 1);
|
||||
//描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色
|
||||
boolean rgbImage = ((rgb >= 0 && rightRgb < 0)
|
||||
|| (rgb < 0 && rightRgb >= 0)
|
||||
|| (rgb >= 0 && downRgb < 0)
|
||||
|| (rgb < 0 && downRgb >= 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param oriImage 原图
|
||||
* @param templateImage 模板图
|
||||
|
@ -3,7 +3,6 @@ package cn.lili.modules.verification;
|
||||
import cn.lili.common.utils.Base64DecodeMultipartFile;
|
||||
import cn.lili.common.vo.SerializableStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@ -21,10 +20,10 @@ import java.util.Random;
|
||||
* @version v4.0
|
||||
* @since 2020/11/17 14:34
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SliderImageUtil {
|
||||
|
||||
|
||||
private static final int BOLD = 5;
|
||||
|
||||
private static final String IMG_FILE_TYPE = "jpg";
|
||||
@ -34,12 +33,18 @@ public class SliderImageUtil {
|
||||
/**
|
||||
* 根据模板切图
|
||||
*
|
||||
* @param sliderFile
|
||||
* @param originalFile
|
||||
* @return
|
||||
* @param sliderFile 滑块
|
||||
* @param originalFile 原图
|
||||
* @param watermark 水印
|
||||
* @param interfereNum 干扰选项
|
||||
* @return 滑块参数
|
||||
* @throws Exception sliderFile, originalFile
|
||||
*/
|
||||
public static Map<String, Object> pictureTemplatesCut(SerializableStream sliderFile, SerializableStream originalFile) throws Exception {
|
||||
public static Map<String, Object> pictureTemplatesCut(
|
||||
SerializableStream sliderFile,
|
||||
SerializableStream interfereSliderFile,
|
||||
SerializableStream originalFile,
|
||||
String watermark, Integer interfereNum) throws Exception {
|
||||
|
||||
Random random = new Random();
|
||||
Map<String, Object> pictureMap = new HashMap<>(16);
|
||||
@ -70,6 +75,18 @@ public class SliderImageUtil {
|
||||
//新建的图像根据模板颜色赋值,源图生成遮罩
|
||||
ImageUtil.cutByTemplate(originalImage, sliderImage, newImage, randomX, randomY);
|
||||
|
||||
|
||||
//干扰项
|
||||
if (interfereNum > 0) {
|
||||
BufferedImage interfereSliderImage = ImageIO.read(Base64DecodeMultipartFile.base64ToInputStream(interfereSliderFile.getBase64()));
|
||||
for (int i = 0; i < interfereNum; i++) {
|
||||
int interfereX = random.nextInt(originalWidth - 3 * sliderWidth) + 2 * sliderWidth;
|
||||
int interfereY = random.nextInt(originalHeight - sliderHeight);
|
||||
ImageUtil.interfereTemplate(originalImage, interfereSliderImage, interfereX, interfereY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//设置“抗锯齿”的属性
|
||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
graphics.setStroke(new BasicStroke(BOLD, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
@ -77,7 +94,7 @@ public class SliderImageUtil {
|
||||
graphics.dispose();
|
||||
|
||||
//添加水印
|
||||
ImageUtil.addWatermark(originalImage, "LILI-SHOP");
|
||||
ImageUtil.addWatermark(originalImage, watermark);
|
||||
//新建流
|
||||
ByteArrayOutputStream newImageOs = new ByteArrayOutputStream();
|
||||
//利用ImageIO类提供的write方法,将bi以png图片的数据模式写入流。
|
||||
|
@ -4,14 +4,15 @@ import cn.lili.cache.Cache;
|
||||
import cn.lili.cache.CachePrefix;
|
||||
import cn.lili.common.enums.ResultCode;
|
||||
import cn.lili.common.exception.ServiceException;
|
||||
import cn.lili.common.properties.VerificationCodeProperties;
|
||||
import cn.lili.common.utils.StringUtils;
|
||||
import cn.lili.modules.verification.SliderImageUtil;
|
||||
import cn.lili.modules.verification.enums.VerificationEnums;
|
||||
import cn.lili.modules.verification.service.VerificationService;
|
||||
import cn.lili.common.vo.SerializableStream;
|
||||
import cn.lili.modules.system.entity.dos.VerificationSource;
|
||||
import cn.lili.modules.system.entity.vo.VerificationDTO;
|
||||
import cn.lili.modules.system.service.VerificationSourceService;
|
||||
import cn.lili.modules.verification.SliderImageUtil;
|
||||
import cn.lili.modules.verification.enums.VerificationEnums;
|
||||
import cn.lili.modules.verification.service.VerificationService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -36,6 +37,11 @@ public class VerificationServiceImpl implements VerificationService {
|
||||
|
||||
@Autowired
|
||||
private VerificationSourceService verificationSourceService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private VerificationCodeProperties verificationCodeProperties;
|
||||
|
||||
@Autowired
|
||||
private Cache cache;
|
||||
|
||||
@ -68,22 +74,30 @@ public class VerificationServiceImpl implements VerificationService {
|
||||
String originalResource = verificationResources.get(resourceNum).getResource();
|
||||
//随机选择剪切模版图片地址
|
||||
String sliderResource = verificationSlider.get(sliderNum).getResource();
|
||||
// 干扰块
|
||||
String interfereResource = verificationSlider.get(sliderNum == verificationSlider.size() - 1 ?
|
||||
sliderNum - 1 : sliderNum + 1).getResource();
|
||||
|
||||
try {
|
||||
//获取缓存中的资源
|
||||
SerializableStream originalFile = getInputStream(originalResource);
|
||||
SerializableStream sliderFile = getInputStream(sliderResource);
|
||||
Map<String, Object> resultMap = SliderImageUtil.pictureTemplatesCut(sliderFile, originalFile);
|
||||
//生成验证参数 120可以验证 无需手动清除,120秒有效时间自动清除
|
||||
cache.put(cacheKey(verificationEnums, uuid), resultMap.get("randomX"), 120L);
|
||||
SerializableStream interfereSliderFile = verificationCodeProperties.getInterfereNum() > 0 ? getInputStream(interfereResource) : null;
|
||||
//生成数据
|
||||
Map<String, Object> resultMap = SliderImageUtil.pictureTemplatesCut(
|
||||
sliderFile, interfereSliderFile, originalFile,
|
||||
verificationCodeProperties.getWatermark(), verificationCodeProperties.getInterfereNum());
|
||||
//生成验证参数 有效时间 默认600秒,可以自行配置
|
||||
cache.put(cacheKey(verificationEnums, uuid), resultMap.get("randomX"), verificationCodeProperties.getEffectiveTime());
|
||||
resultMap.put("key", cacheKey(verificationEnums, uuid));
|
||||
resultMap.put("effectiveTime", verificationCodeProperties.getEffectiveTime());
|
||||
//移除横坐标移动距离
|
||||
resultMap.remove("randomX");
|
||||
return resultMap;
|
||||
} catch (ServiceException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("创建校验错误",e);
|
||||
log.error("创建校验错误", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -91,6 +105,7 @@ public class VerificationServiceImpl implements VerificationService {
|
||||
/**
|
||||
* 根据网络地址,获取源文件
|
||||
* 这里简单说一下,这里是将不可序列化的inputstream序列化对象,存入redis缓存
|
||||
*
|
||||
* @param originalResource
|
||||
* @return
|
||||
*/
|
||||
@ -125,11 +140,10 @@ public class VerificationServiceImpl implements VerificationService {
|
||||
}
|
||||
log.debug("{}{}", randomX, xPos);
|
||||
//验证结果
|
||||
boolean result = Math.abs(randomX - xPos) < 3;
|
||||
if (result) {
|
||||
//验证成功,则记录验证结果 验证有效时间,120秒
|
||||
cache.put(cacheResult(verificationEnums, uuid), true, 120L);
|
||||
return result;
|
||||
if (Math.abs(randomX - xPos) < verificationCodeProperties.getFaultTolerant()) {
|
||||
//验证成功,则记录验证结果 验证有效时间与验证码创建有效时间一致
|
||||
cache.put(cacheResult(verificationEnums, uuid), true, verificationCodeProperties.getEffectiveTime());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user