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