U 优化点选验证码,用于将来支持语序验证码等相关具有联想的点击类验证码

This commit is contained in:
天爱有情
2022-05-27 11:48:40 +08:00
parent 3377d55ead
commit bf5b8987f2
2 changed files with 56 additions and 31 deletions
@@ -31,7 +31,6 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
@Setter
protected Integer interferenceCount = 2;
public AbstractClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager) {
super(imageCaptchaResourceManager);
}
@@ -53,9 +52,13 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
List<ClickImageCheckDefinition> clickImageCheckDefinitionList = new ArrayList<>(interferenceCount);
int allImages = interferenceCount + checkClickCount;
int avg = bgImage.getWidth() / allImages;
List<String> imgTips = randomGetClickImgTips(allImages);
if (allImages < imgTips.size()) {
throw new IllegalStateException("随机生成点击图片小于请求数量, 请求生成数量=" + allImages + ",实际生成数量=" + imgTips.size());
}
for (int i = 0; i < allImages; i++) {
// 随机获取点击图片
ImgWrapper imgWrapper = randomGetClickImg();
ImgWrapper imgWrapper = getClickImg(imgTips.get(i));
BufferedImage image = imgWrapper.getImage();
int clickImgWidth = image.getWidth();
int clickImgHeight = image.getHeight();
@@ -78,17 +81,10 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
clickImageCheckDefinition.setHeight(clickImgHeight);
clickImageCheckDefinitionList.add(clickImageCheckDefinition);
}
// 打乱
Collections.shuffle(clickImageCheckDefinitionList);
// 拿出参与校验的数据
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = new ArrayList<>(checkClickCount);
for (int i = 0; i < checkClickCount; i++) {
ClickImageCheckDefinition clickImageCheckDefinition = clickImageCheckDefinitionList.get(i);
checkClickImageCheckDefinitionList.add(clickImageCheckDefinition);
}
// 将校验的文字生成提示图片
ImgWrapper tipImage = genTipImage(checkClickImageCheckDefinitionList);
return wrapClickImageCaptchaInfo(param, bgImage, tipImage.getImage(), checkClickImageCheckDefinitionList);
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = getCheckClickImageCheckDefinitionList(clickImageCheckDefinitionList,
checkClickCount);
// wrap
return wrapClickImageCaptchaInfo(param, bgImage, checkClickImageCheckDefinitionList);
} finally {
// 使用完后关闭流
@@ -103,31 +99,50 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
}
/**
* 随机获取点击的图片
* 从总的图片中 去除要校验的图片数据 以及顺序
*
* @return ImgWrapper
* @param allCheckDefinitionList 总的点选图片
* @param checkClickCount 参与校验的数据
* @return List<ClickImageCheckDefinition>
*/
public abstract ImgWrapper randomGetClickImg();
protected List<ClickImageCheckDefinition> getCheckClickImageCheckDefinitionList(List<ClickImageCheckDefinition> allCheckDefinitionList,
Integer checkClickCount) {
// 打乱
Collections.shuffle(allCheckDefinitionList);
// 拿出参与校验的数据
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = new ArrayList<>(checkClickCount);
for (int i = 0; i < checkClickCount; i++) {
ClickImageCheckDefinition clickImageCheckDefinition = allCheckDefinitionList.get(i);
checkClickImageCheckDefinitionList.add(clickImageCheckDefinition);
}
return checkClickImageCheckDefinitionList;
}
/**
* 生成 tip 图片
* 随机获取一组数据用于生成随机图
*
* @param imageCheckDefinitions imageCheckDefinitions
* @param tipSize tipSize
* @return List<String>
*/
protected abstract List<String> randomGetClickImgTips(int tipSize);
/**
* 随机获取点击的图片
*
* @param tip 提示数据,根据改数据生成图片
* @return ImgWrapper
*/
public abstract ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions);
public abstract ImgWrapper getClickImg(String tip);
/**
* 包装 ImageCaptchaInfo
*
* @param param param
* @param bgImage bgImage
* @param tipImage tipImage
* @param checkClickImageCheckDefinitionList checkClickImageCheckDefinitionList
* @return ImageCaptchaInfo
*/
public abstract ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
BufferedImage tipImage,
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList);
/**
@@ -18,6 +18,7 @@ import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
@@ -47,8 +48,8 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
protected int tipImageInterferencePointNum = 5;
/**
* 因为在画文字图形的时候 y 值不能准确通过 除法计算得出, 字体大小不一致中间的容错值不可估计,
* 所以通过 线性回归模型 计算出 intercept和coef 用于计算 容错值
* 因为在画文字图形的时候 y 值不能准确通过 除法计算得出, 字体大小不一致中间的容错值算不准确
* 方案: 通过 线性回归模型 计算出 intercept和coef 用于计算 容错值
* 训练数据为 宋体 字体大小为 30~150 随机选择7组数据进行训练, 训练后r2结果为 0.9967106324620846
*/
protected float intercept = 0.39583333f;
@@ -63,6 +64,18 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
}
@Override
protected List<String> randomGetClickImgTips(int tipSize) {
ThreadLocalRandom random = ThreadLocalRandom.current();
List<String> tipList = new ArrayList<>(tipSize);
for (int i = 0; i < tipSize; i++) {
String randomWord = FontUtils.getRandomChar(random);
tipList.add(randomWord);
}
// 随机文字
return tipList;
}
@Override
@SneakyThrows({IOException.class, FontFormatException.class})
protected void doInit(boolean initDefaultResource) {
@@ -85,14 +98,12 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
this.font = font;
}
public void initDefaultResource() {
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
// 添加一些系统的资源文件
resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
}
@Override
public ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions) {
String tips = imageCheckDefinitions.stream().map(ClickImageCheckDefinition::getTip).collect(Collectors.joining());
// 生成随机颜色
@@ -107,29 +118,28 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
}
@Override
public ImgWrapper randomGetClickImg() {
public ImgWrapper getClickImg(String tip) {
ThreadLocalRandom random = ThreadLocalRandom.current();
// 随机文字
String randomWord = FontUtils.getRandomChar(random);
// 随机颜色
Color randomColor = CaptchaImageUtils.getRandomColor(random);
// 随机角度
int randomDeg = ThreadLocalRandom.current().nextInt(0, 85);
BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor,
randomWord,
tip,
font,
currentFontTopCoef,
clickImgWidth,
clickImgHeight,
randomDeg);
return new ImgWrapper(fontImage, randomWord);
return new ImgWrapper(fontImage, tip);
}
@Override
public ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
BufferedImage tipImage,
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList) {
// 提示图片
BufferedImage tipImage = genTipImage(checkClickImageCheckDefinitionList).getImage();
ImageCaptchaInfo clickImageCaptchaInfo = new ImageCaptchaInfo();
clickImageCaptchaInfo.setBackgroundImage(transform(bgImage, param.getBackgroundFormatName()));
clickImageCaptchaInfo.setSliderImage(transform(tipImage, param.getSliderFormatName()));