mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
优化
This commit is contained in:
+2
@@ -15,4 +15,6 @@ public interface CaptchaTypeConstant {
|
|||||||
String CONCAT = "CONCAT";
|
String CONCAT = "CONCAT";
|
||||||
/** 图片点选.*/
|
/** 图片点选.*/
|
||||||
String IMAGE_CLICK = "IMAGE_CLICK";
|
String IMAGE_CLICK = "IMAGE_CLICK";
|
||||||
|
/** 文字图片点选.*/
|
||||||
|
String WORD_IMAGE_CLICK = "WORD_IMAGE_CLICK";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class CaptchaUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否是滑动验证码
|
* 是否是滑动验证码
|
||||||
|
*
|
||||||
* @param type 类型
|
* @param type 类型
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
@@ -22,11 +23,12 @@ public class CaptchaUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否是点击验证码
|
* 是否是点击验证码
|
||||||
|
*
|
||||||
* @param type type
|
* @param type type
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public static boolean isClickCaptcha(String type) {
|
public static boolean isClickCaptcha(String type) {
|
||||||
return CaptchaTypeConstant.IMAGE_CLICK.equals(type);
|
return CaptchaTypeConstant.WORD_IMAGE_CLICK.equals(type) || CaptchaTypeConstant.IMAGE_CLICK.equals(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -15,6 +15,7 @@ public interface ImageCaptchaGenerator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成验证码图片
|
* 生成验证码图片
|
||||||
|
*
|
||||||
* @param type 类型 {@link CaptchaTypeConstant}
|
* @param type 类型 {@link CaptchaTypeConstant}
|
||||||
* @return SliderCaptchaInfo
|
* @return SliderCaptchaInfo
|
||||||
*/
|
*/
|
||||||
@@ -23,6 +24,7 @@ public interface ImageCaptchaGenerator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成滑块验证码
|
* 生成滑块验证码
|
||||||
|
*
|
||||||
* @param type type {@link CaptchaTypeConstant}
|
* @param type type {@link CaptchaTypeConstant}
|
||||||
* @param targetFormatName jpeg或者webp格式
|
* @param targetFormatName jpeg或者webp格式
|
||||||
* @param matrixFormatName png或者webp格式
|
* @param matrixFormatName png或者webp格式
|
||||||
|
|||||||
+2
@@ -36,6 +36,8 @@ public class ImageCaptchaInfo {
|
|||||||
private Float tolerant;
|
private Float tolerant;
|
||||||
/** 验证码类型. */
|
/** 验证码类型. */
|
||||||
private String type;
|
private String type;
|
||||||
|
/** 透传字段,用于传给前端.*/
|
||||||
|
private Object data;
|
||||||
/**
|
/**
|
||||||
* 扩展字段
|
* 扩展字段
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
@@ -406,6 +406,7 @@ public class CaptchaImageUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成简单的验证码图片
|
* 生成简单的验证码图片
|
||||||
|
*
|
||||||
* @param data 验证码内容
|
* @param data 验证码内容
|
||||||
* @param font 字体包
|
* @param font 字体包
|
||||||
* @param metrics FontDesignMetrics
|
* @param metrics FontDesignMetrics
|
||||||
@@ -450,6 +451,7 @@ public class CaptchaImageUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 随机获取颜色
|
* 随机获取颜色
|
||||||
|
*
|
||||||
* @return Color
|
* @return Color
|
||||||
*/
|
*/
|
||||||
public static Color getRandomColor(Random random) {
|
public static Color getRandomColor(Random random) {
|
||||||
|
|||||||
+40
-45
@@ -1,23 +1,16 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
||||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.*;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
@@ -28,12 +21,15 @@ import static cloud.tianai.captcha.template.slider.generator.common.util.Captcha
|
|||||||
* @date 2022/4/27 11:46
|
* @date 2022/4/27 11:46
|
||||||
* @Description 点选验证码 点选验证码分为点选文字和点选图标等
|
* @Description 点选验证码 点选验证码分为点选文字和点选图标等
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||||
|
|
||||||
/** 参与校验的数量. */
|
/** 参与校验的数量. */
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
protected Integer checkClickCount = 4;
|
protected Integer checkClickCount = 4;
|
||||||
/** 干扰数量. */
|
/** 干扰数量. */
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
protected Integer interferenceCount = 2;
|
protected Integer interferenceCount = 2;
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@@ -49,6 +45,7 @@ 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;
|
||||||
for (int i = 0; i < allImages; i++) {
|
for (int i = 0; i < allImages; i++) {
|
||||||
// 随机获取点击图片
|
// 随机获取点击图片
|
||||||
ImgWrapper imgWrapper = randomGetClickImg();
|
ImgWrapper imgWrapper = randomGetClickImg();
|
||||||
@@ -56,12 +53,16 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
int clickImgWidth = image.getWidth();
|
int clickImgWidth = image.getWidth();
|
||||||
int clickImgHeight = image.getHeight();
|
int clickImgHeight = image.getHeight();
|
||||||
// 随机x
|
// 随机x
|
||||||
int randomX = ThreadLocalRandom.current().nextInt(10, bgImage.getWidth() - clickImgWidth);
|
int randomX;
|
||||||
|
if (i == 0) {
|
||||||
|
randomX = 1;
|
||||||
|
} else {
|
||||||
|
randomX = avg * i;
|
||||||
|
}
|
||||||
// 随机y
|
// 随机y
|
||||||
int randomY = ThreadLocalRandom.current().nextInt(10, bgImage.getHeight() - clickImgHeight);
|
int randomY = ThreadLocalRandom.current().nextInt(10, bgImage.getHeight() - clickImgHeight);
|
||||||
// 通过随机x和y 进行覆盖图片
|
// 通过随机x和y 进行覆盖图片
|
||||||
CaptchaImageUtils.overlayImage(bgImage, imgWrapper.getImage(), randomX, randomY);
|
CaptchaImageUtils.overlayImage(bgImage, imgWrapper.getImage(), randomX, randomY);
|
||||||
ImageIO.write(imgWrapper.getImage(), "png", new FileOutputStream("C:\\Users\\tianai\\Desktop\\111\\" + i + ".png"));
|
|
||||||
ClickImageCheckDefinition clickImageCheckDefinition = new ClickImageCheckDefinition();
|
ClickImageCheckDefinition clickImageCheckDefinition = new ClickImageCheckDefinition();
|
||||||
clickImageCheckDefinition.setTip(imgWrapper.getTip());
|
clickImageCheckDefinition.setTip(imgWrapper.getTip());
|
||||||
clickImageCheckDefinition.setX(randomX + clickImgWidth / 2);
|
clickImageCheckDefinition.setX(randomX + clickImgWidth / 2);
|
||||||
@@ -70,14 +71,6 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
clickImageCheckDefinition.setHeight(clickImgHeight);
|
clickImageCheckDefinition.setHeight(clickImgHeight);
|
||||||
clickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
clickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
||||||
}
|
}
|
||||||
// 背景图转换为字符串
|
|
||||||
// String bgImageStr = transform(bgImage, param.getBackgroundFormatName());
|
|
||||||
try {
|
|
||||||
ImageIO.write(bgImage, "jpeg", new FileOutputStream("C:\\Users\\tianai\\Desktop\\123.jpg"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打乱
|
// 打乱
|
||||||
Collections.shuffle(clickImageCheckDefinitionList);
|
Collections.shuffle(clickImageCheckDefinitionList);
|
||||||
// 拿出参与校验的数据
|
// 拿出参与校验的数据
|
||||||
@@ -88,12 +81,6 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
}
|
}
|
||||||
// 将校验的文字生成提示图片
|
// 将校验的文字生成提示图片
|
||||||
ImgWrapper tipImage = genTipImage(checkClickImageCheckDefinitionList);
|
ImgWrapper tipImage = genTipImage(checkClickImageCheckDefinitionList);
|
||||||
|
|
||||||
try {
|
|
||||||
ImageIO.write(tipImage.getImage(), "png", new FileOutputStream("C:\\Users\\tianai\\Desktop\\456.png"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return wrapClickImageCaptchaInfo(param, bgImage, tipImage.getImage(), checkClickImageCheckDefinitionList);
|
return wrapClickImageCaptchaInfo(param, bgImage, tipImage.getImage(), checkClickImageCheckDefinitionList);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
@@ -110,26 +97,34 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
// return null;
|
// return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
|
|
||||||
|
/**
|
||||||
|
* 随机获取点击的图片
|
||||||
|
*
|
||||||
|
* @return ImgWrapper
|
||||||
|
*/
|
||||||
|
public abstract ImgWrapper randomGetClickImg();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成 tip 图片
|
||||||
|
*
|
||||||
|
* @param imageCheckDefinitions imageCheckDefinitions
|
||||||
|
* @return ImgWrapper
|
||||||
|
*/
|
||||||
|
public abstract ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包装 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,
|
BufferedImage tipImage,
|
||||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList) {
|
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList);
|
||||||
ImageCaptchaInfo clickImageCaptchaInfo = new ImageCaptchaInfo();
|
|
||||||
clickImageCaptchaInfo.setBackgroundImage(transform(bgImage, param.getBackgroundFormatName()));
|
|
||||||
clickImageCaptchaInfo.setSliderImage(transform(bgImage, param.getSliderFormatName()));
|
|
||||||
clickImageCaptchaInfo.setBgImageWidth(bgImage.getWidth());
|
|
||||||
clickImageCaptchaInfo.setBgImageHeight(bgImage.getHeight());
|
|
||||||
clickImageCaptchaInfo.setSliderImageWidth(tipImage.getWidth());
|
|
||||||
clickImageCaptchaInfo.setSliderImageHeight(tipImage.getHeight());
|
|
||||||
clickImageCaptchaInfo.setRandomX(null);
|
|
||||||
clickImageCaptchaInfo.setTolerant(null);
|
|
||||||
clickImageCaptchaInfo.setType(CaptchaTypeConstant.IMAGE_CLICK);
|
|
||||||
clickImageCaptchaInfo.setExpand(checkClickImageCheckDefinitionList);
|
|
||||||
return clickImageCaptchaInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions);
|
|
||||||
|
|
||||||
protected abstract ImgWrapper randomGetClickImg();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
|
|||||||
+5
-1
@@ -1,9 +1,9 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||||
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
||||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator;
|
import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
||||||
@@ -24,6 +24,7 @@ public class MultiImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
|||||||
private boolean initDefaultResource;
|
private boolean initDefaultResource;
|
||||||
|
|
||||||
private String defaultCaptcha = CaptchaTypeConstant.SLIDER;
|
private String defaultCaptcha = CaptchaTypeConstant.SLIDER;
|
||||||
|
|
||||||
public MultiImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
|
public MultiImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
|
||||||
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
|
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
|
||||||
this.initDefaultResource = initDefaultResource;
|
this.initDefaultResource = initDefaultResource;
|
||||||
@@ -37,11 +38,14 @@ public class MultiImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
|||||||
addImageCaptchaGenerator(CaptchaTypeConstant.ROTATE, new StandardRotateImageCaptchaGenerator(imageCaptchaResourceManager, initDefaultResource));
|
addImageCaptchaGenerator(CaptchaTypeConstant.ROTATE, new StandardRotateImageCaptchaGenerator(imageCaptchaResourceManager, initDefaultResource));
|
||||||
// 拼接验证码
|
// 拼接验证码
|
||||||
addImageCaptchaGenerator(CaptchaTypeConstant.CONCAT, new StandardConcatImageCaptchaGenerator(imageCaptchaResourceManager, initDefaultResource));
|
addImageCaptchaGenerator(CaptchaTypeConstant.CONCAT, new StandardConcatImageCaptchaGenerator(imageCaptchaResourceManager, initDefaultResource));
|
||||||
|
// 点选文字验证码
|
||||||
|
addImageCaptchaGenerator(CaptchaTypeConstant.WORD_IMAGE_CLICK, new StandardRandomWordClickImageCaptchaGenerator(imageCaptchaResourceManager, initDefaultResource));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addImageCaptchaGenerator(String key, ImageCaptchaGenerator captchaGenerator) {
|
public void addImageCaptchaGenerator(String key, ImageCaptchaGenerator captchaGenerator) {
|
||||||
imageCaptchaGeneratorMap.put(key, captchaGenerator);
|
imageCaptchaGeneratorMap.put(key, captchaGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageCaptchaGenerator removeImageCaptchaGenerator(String key) {
|
public ImageCaptchaGenerator removeImageCaptchaGenerator(String key) {
|
||||||
return imageCaptchaGeneratorMap.remove(key);
|
return imageCaptchaGeneratorMap.remove(key);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-14
@@ -1,7 +1,7 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
|
||||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
||||||
@@ -51,18 +51,19 @@ public class StandardConcatImageCaptchaGenerator extends AbstractImageCaptchaGen
|
|||||||
InputStream resourceInputStream = imageCaptchaResourceManager.getResourceInputStream(resourceImage);
|
InputStream resourceInputStream = imageCaptchaResourceManager.getResourceInputStream(resourceImage);
|
||||||
inputStreams.add(resourceInputStream);
|
inputStreams.add(resourceInputStream);
|
||||||
BufferedImage bgImage = wrapFile2BufferedImage(resourceInputStream);
|
BufferedImage bgImage = wrapFile2BufferedImage(resourceInputStream);
|
||||||
int spacing = bgImage.getHeight() / 4;
|
int spacingY = bgImage.getHeight() / 4;
|
||||||
BufferedImage[] bgImageSplit = splitImage(ThreadLocalRandom.current().nextInt(spacing, bgImage.getHeight() - spacing), true, bgImage);
|
int randomY = ThreadLocalRandom.current().nextInt(spacingY, bgImage.getHeight() - spacingY);
|
||||||
|
BufferedImage[] bgImageSplit = splitImage(randomY, true, bgImage);
|
||||||
spacing = bgImage.getWidth() / 8;
|
int spacingX = bgImage.getWidth() / 8;
|
||||||
int randomX = ThreadLocalRandom.current().nextInt(spacing, bgImage.getWidth() - spacing);
|
int randomX = ThreadLocalRandom.current().nextInt(spacingX, bgImage.getWidth() - bgImage.getWidth() / 5);
|
||||||
BufferedImage[] bgImageTopSplit = splitImage(randomX, false, bgImageSplit[0]);
|
BufferedImage[] bgImageTopSplit = splitImage(randomX, false, bgImageSplit[0]);
|
||||||
|
|
||||||
BufferedImage sliderImage = concatImage(true,
|
BufferedImage sliderImage = concatImage(true,
|
||||||
bgImageTopSplit[0].getWidth()
|
bgImageTopSplit[0].getWidth()
|
||||||
+ bgImageTopSplit[1].getWidth()
|
+ bgImageTopSplit[1].getWidth(), bgImageTopSplit[0].getHeight(), bgImageTopSplit[1], bgImageTopSplit[0]);
|
||||||
+ bgImageSplit[0].getWidth(), bgImageTopSplit[1].getHeight(), bgImageSplit[0], bgImageTopSplit[0]);
|
bgImage = concatImage(false, bgImageSplit[1].getWidth(), sliderImage.getHeight() + bgImageSplit[1].getHeight(),
|
||||||
return wrapConcatCaptchaInfo(randomX, bgImageSplit[1], sliderImage, param);
|
sliderImage, bgImageSplit[1]);
|
||||||
|
return wrapConcatCaptchaInfo(randomX, randomY,bgImage, param);
|
||||||
} finally {
|
} finally {
|
||||||
// 使用完后关闭流
|
// 使用完后关闭流
|
||||||
for (InputStream inputStream : inputStreams) {
|
for (InputStream inputStream : inputStreams) {
|
||||||
@@ -76,17 +77,17 @@ public class StandardConcatImageCaptchaGenerator extends AbstractImageCaptchaGen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private ImageCaptchaInfo wrapConcatCaptchaInfo(int randomX, BufferedImage bgImage, BufferedImage sliderImage, GenerateParam param) {
|
private ImageCaptchaInfo wrapConcatCaptchaInfo(int randomX, int randomY, BufferedImage bgImage, GenerateParam param) {
|
||||||
String backGroundImageBase64 = transform(bgImage, param.getBackgroundFormatName());
|
String backGroundImageBase64 = transform(bgImage, param.getBackgroundFormatName());
|
||||||
String sliderImageBase64 = transform(sliderImage, param.getSliderFormatName());
|
|
||||||
ImageCaptchaInfo imageCaptchaInfo = ImageCaptchaInfo.of(backGroundImageBase64,
|
ImageCaptchaInfo imageCaptchaInfo = ImageCaptchaInfo.of(backGroundImageBase64,
|
||||||
sliderImageBase64,
|
null,
|
||||||
bgImage.getWidth(),
|
bgImage.getWidth(),
|
||||||
bgImage.getHeight(),
|
bgImage.getHeight(),
|
||||||
sliderImage.getWidth(),
|
null,
|
||||||
sliderImage.getHeight(),
|
null,
|
||||||
randomX,
|
randomX,
|
||||||
CaptchaTypeConstant.CONCAT);
|
CaptchaTypeConstant.CONCAT);
|
||||||
|
imageCaptchaInfo.setData(randomY);
|
||||||
imageCaptchaInfo.setTolerant(0.05F);
|
imageCaptchaInfo.setTolerant(0.05F);
|
||||||
return imageCaptchaInfo;
|
return imageCaptchaInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-10
@@ -1,9 +1,11 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
|
||||||
import cloud.tianai.captcha.template.slider.common.util.FontUtils;
|
|
||||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.common.util.FontUtils;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
||||||
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
||||||
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
@@ -33,8 +35,8 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
/** 字体包. */
|
/** 字体包. */
|
||||||
protected Font font;
|
protected Font font;
|
||||||
protected FontDesignMetrics metrics;
|
protected FontDesignMetrics metrics;
|
||||||
protected Integer clickImgWidth = 60;
|
protected Integer clickImgWidth = 80;
|
||||||
protected Integer clickImgHeight = 60;
|
protected Integer clickImgHeight = 80;
|
||||||
protected int tipImageInterferenceLineNum = 2;
|
protected int tipImageInterferenceLineNum = 2;
|
||||||
protected int tipImageInterferencePointNum = 5;
|
protected int tipImageInterferencePointNum = 5;
|
||||||
|
|
||||||
@@ -48,11 +50,11 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
Resource fontResource = new Resource(null, "META-INF/fonts/SIMSUN.TTC");
|
Resource fontResource = new Resource(null, "META-INF/fonts/SIMSUN.TTC");
|
||||||
InputStream inputStream = new ClassPathResourceProvider().doGetResourceInputStream(fontResource);
|
InputStream inputStream = new ClassPathResourceProvider().doGetResourceInputStream(fontResource);
|
||||||
Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
|
Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
|
||||||
font = font.deriveFont(Font.BOLD, 50);
|
font = font.deriveFont(Font.BOLD, 70);
|
||||||
this.metrics = FontDesignMetrics.getMetrics(font);
|
this.metrics = FontDesignMetrics.getMetrics(font);
|
||||||
this.font = font;
|
this.font = font;
|
||||||
setClickImgHeight(60);
|
setClickImgHeight(clickImgWidth);
|
||||||
setClickImgWidth(60);
|
setClickImgWidth(clickImgHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StandardRandomWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager,
|
public StandardRandomWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager,
|
||||||
@@ -71,11 +73,11 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
public void initDefaultResource() {
|
public void initDefaultResource() {
|
||||||
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
|
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
|
||||||
// 添加一些系统的资源文件
|
// 添加一些系统的资源文件
|
||||||
resourceStore.addResource(CaptchaTypeConstant.IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected 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());
|
||||||
// 生成随机颜色
|
// 生成随机颜色
|
||||||
int fontWidth = metrics.stringWidth(tips);
|
int fontWidth = metrics.stringWidth(tips);
|
||||||
@@ -89,7 +91,7 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ImgWrapper randomGetClickImg() {
|
public ImgWrapper randomGetClickImg() {
|
||||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
// 随机文字
|
// 随机文字
|
||||||
String randomWord = FontUtils.getRandomChar(random);
|
String randomWord = FontUtils.getRandomChar(random);
|
||||||
@@ -107,6 +109,25 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
return new ImgWrapper(fontImage, randomWord);
|
return new ImgWrapper(fontImage, randomWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
|
||||||
|
BufferedImage tipImage,
|
||||||
|
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList) {
|
||||||
|
ImageCaptchaInfo clickImageCaptchaInfo = new ImageCaptchaInfo();
|
||||||
|
clickImageCaptchaInfo.setBackgroundImage(transform(bgImage, param.getBackgroundFormatName()));
|
||||||
|
clickImageCaptchaInfo.setSliderImage(transform(tipImage, param.getSliderFormatName()));
|
||||||
|
clickImageCaptchaInfo.setBgImageWidth(bgImage.getWidth());
|
||||||
|
clickImageCaptchaInfo.setBgImageHeight(bgImage.getHeight());
|
||||||
|
clickImageCaptchaInfo.setSliderImageWidth(tipImage.getWidth());
|
||||||
|
clickImageCaptchaInfo.setSliderImageHeight(tipImage.getHeight());
|
||||||
|
clickImageCaptchaInfo.setRandomX(null);
|
||||||
|
clickImageCaptchaInfo.setTolerant(null);
|
||||||
|
clickImageCaptchaInfo.setType(CaptchaTypeConstant.WORD_IMAGE_CLICK);
|
||||||
|
clickImageCaptchaInfo.setExpand(checkClickImageCheckDefinitionList);
|
||||||
|
return clickImageCaptchaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageCaptchaResourceManager getImageResourceManager() {
|
public ImageCaptchaResourceManager getImageResourceManager() {
|
||||||
return imageCaptchaResourceManager;
|
return imageCaptchaResourceManager;
|
||||||
|
|||||||
+1
-33
@@ -1,8 +1,7 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
|
||||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
@@ -13,10 +12,7 @@ import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
|||||||
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
|
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -61,7 +57,6 @@ public class StandardRotateImageCaptchaGenerator extends AbstractImageCaptchaGen
|
|||||||
@Override
|
@Override
|
||||||
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||||
// 旋转验证码没有混淆
|
// 旋转验证码没有混淆
|
||||||
Boolean obfuscate = param.getObfuscate();
|
|
||||||
Map<String, Resource> templateImages = imageCaptchaResourceManager.randomGetTemplate(param.getType());
|
Map<String, Resource> templateImages = imageCaptchaResourceManager.randomGetTemplate(param.getType());
|
||||||
if (templateImages == null || templateImages.isEmpty()) {
|
if (templateImages == null || templateImages.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -128,36 +123,9 @@ public class StandardRotateImageCaptchaGenerator extends AbstractImageCaptchaGen
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
|
|
||||||
// FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\aa" + formatType + "." + formatType);
|
|
||||||
// ImageIO.write(bufferedImage, formatType, fileOutputStream);
|
|
||||||
// fileOutputStream.close();
|
|
||||||
//// return super.transform(bufferedImage, formatType);
|
|
||||||
// return "";
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageCaptchaResourceManager getImageResourceManager() {
|
public ImageCaptchaResourceManager getImageResourceManager() {
|
||||||
return imageCaptchaResourceManager;
|
return imageCaptchaResourceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
|
||||||
BufferedImage bgImage = CaptchaImageUtils.wrapFile2BufferedImage(
|
|
||||||
new FileInputStream("E:\\projects\\tianai-captcha\\src\\main\\resources\\META-INF\\cut-image\\resource\\1.jpg"));
|
|
||||||
BufferedImage image1 = CaptchaImageUtils.wrapFile2BufferedImage(new FileInputStream("C:\\Users\\Thinkpad\\Desktop\\a.png"));
|
|
||||||
BufferedImage image2 = CaptchaImageUtils.wrapFile2BufferedImage(new FileInputStream("C:\\Users\\Thinkpad\\Desktop\\b.png"));
|
|
||||||
|
|
||||||
BufferedImage cutImage = CaptchaImageUtils.cutImage(bgImage, image1, bgImage.getWidth() / 2 - 100, bgImage.getHeight() / 2 - 100);
|
|
||||||
CaptchaImageUtils.overlayImage(cutImage, image2, 0, 0);
|
|
||||||
cutImage = CaptchaImageUtils.rotateImage(cutImage, 180);
|
|
||||||
CaptchaImageUtils.overlayImage(bgImage, image1, bgImage.getWidth() / 2 - 100, bgImage.getHeight() / 2 - 100);
|
|
||||||
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\a1.jpg");
|
|
||||||
FileOutputStream file2OutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\a2.png");
|
|
||||||
ImageIO.write(bgImage, "jpeg", fileOutputStream);
|
|
||||||
ImageIO.write(cutImage, "png", file2OutputStream);
|
|
||||||
fileOutputStream.close();
|
|
||||||
file2OutputStream.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
|
||||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
package cloud.tianai.captcha.template.slider.resource;
|
package cloud.tianai.captcha.template.slider.resource;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.resource.ResourceProvider;
|
|
||||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.validator.common.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2022/4/29 8:33
|
||||||
|
* @Description 滑动轨迹类型
|
||||||
|
*/
|
||||||
|
public interface TrackTypeConstant {
|
||||||
|
|
||||||
|
/** 抬起.*/
|
||||||
|
String UP = "UP";
|
||||||
|
/** 按下.*/
|
||||||
|
String DOWN = "DOWN";
|
||||||
|
/** 移动.*/
|
||||||
|
String MOVE = "MOVE";
|
||||||
|
/** 点击.*/
|
||||||
|
String CLICK = "CLICK";
|
||||||
|
}
|
||||||
+6
@@ -1,5 +1,6 @@
|
|||||||
package cloud.tianai.captcha.template.slider.validator.common.model.dto;
|
package cloud.tianai.captcha.template.slider.validator.common.model.dto;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.validator.common.constant.TrackTypeConstant;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@@ -35,8 +36,13 @@ public class SliderCaptchaTrack {
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class Track {
|
public static class Track {
|
||||||
|
/** x. */
|
||||||
private Integer x;
|
private Integer x;
|
||||||
|
/** y. */
|
||||||
private Integer y;
|
private Integer y;
|
||||||
|
/** 时间. */
|
||||||
private Integer t;
|
private Integer t;
|
||||||
|
/** 类型. */
|
||||||
|
private String type = TrackTypeConstant.MOVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-8
@@ -1,5 +1,6 @@
|
|||||||
package cloud.tianai.captcha.template.slider.validator.impl;
|
package cloud.tianai.captcha.template.slider.validator.impl;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.common.util.CaptchaUtils;
|
||||||
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
||||||
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
||||||
@@ -22,13 +23,17 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
public boolean beforeValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
// 校验参数
|
// 校验参数
|
||||||
checkParam(sliderCaptchaTrack);
|
checkParam(sliderCaptchaTrack);
|
||||||
// 基础校验
|
return true;
|
||||||
boolean superValid = super.valid(sliderCaptchaTrack, sliderCaptchaValidData);
|
}
|
||||||
if (!superValid) {
|
|
||||||
return false;
|
@Override
|
||||||
|
public boolean afterValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
|
if (!CaptchaUtils.isSliderCaptcha(type)){
|
||||||
|
// 不是滑动验证码的话暂时跳过,点选验证码行为轨迹还没做
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// 进行行为轨迹检测
|
// 进行行为轨迹检测
|
||||||
long startSlidingTime = sliderCaptchaTrack.getStartSlidingTime().getTime();
|
long startSlidingTime = sliderCaptchaTrack.getStartSlidingTime().getTime();
|
||||||
@@ -93,7 +98,6 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
|||||||
return endAvgPosTime > startAvgPosTime;
|
return endAvgPosTime > startAvgPosTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void checkParam(SliderCaptchaTrack sliderCaptchaTrack) {
|
public void checkParam(SliderCaptchaTrack sliderCaptchaTrack) {
|
||||||
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getBgImageWidth())) {
|
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getBgImageWidth())) {
|
||||||
throw new IllegalArgumentException("bgImageWidth must not be null");
|
throw new IllegalArgumentException("bgImageWidth must not be null");
|
||||||
@@ -120,8 +124,9 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
|||||||
Integer x = track.getX();
|
Integer x = track.getX();
|
||||||
Integer y = track.getY();
|
Integer y = track.getY();
|
||||||
Integer t = track.getT();
|
Integer t = track.getT();
|
||||||
if (x == null || y == null || t == null) {
|
String type = track.getType();
|
||||||
throw new IllegalArgumentException("track[x,y,t] must not be null");
|
if (x == null || y == null || t == null || ObjectUtils.isEmpty(type)) {
|
||||||
|
throw new IllegalArgumentException("track[x,y,t,type] must not be null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-19
@@ -7,6 +7,7 @@ import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
|||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.validator.ImageCaptchaValidator;
|
import cloud.tianai.captcha.template.slider.validator.ImageCaptchaValidator;
|
||||||
|
import cloud.tianai.captcha.template.slider.validator.common.constant.TrackTypeConstant;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -15,6 +16,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
@@ -25,15 +27,15 @@ import java.util.Map;
|
|||||||
public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||||
|
|
||||||
public static float DEFAULT_TOLERANT = 0.02f;
|
public static float DEFAULT_TOLERANT = 0.02f;
|
||||||
|
public static final String PERCENTAGE_KEY = "percentage";
|
||||||
|
public static final String TOLERANT_KEY = "tolerant";
|
||||||
|
public static final String TYPE_KEY = "type";
|
||||||
|
|
||||||
/** 容错值. */
|
/** 容错值. */
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public float defaultTolerant = DEFAULT_TOLERANT;
|
public float defaultTolerant = DEFAULT_TOLERANT;
|
||||||
|
|
||||||
public static final String PERCENTAGE_KEY = "percentage";
|
|
||||||
public static final String TOLERANT_KEY = "Tolerant";
|
|
||||||
public static final String TYPE_KEY = "type";
|
|
||||||
|
|
||||||
public SimpleImageCaptchaValidator() {
|
public SimpleImageCaptchaValidator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +68,14 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Object> generateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
public Map<String, Object> generateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
||||||
Map<String, Object> map = new HashMap<>(8);
|
Map<String, Object> map = new HashMap<>(8);
|
||||||
|
if(beforeGenerateImageCaptchaValidData(imageCaptchaInfo, map)) {
|
||||||
|
doGenerateImageCaptchaValidData(map, imageCaptchaInfo);
|
||||||
|
}
|
||||||
|
afterGenerateImageCaptchaValidData(imageCaptchaInfo, map);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean beforeGenerateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo, Map<String, Object> map) {
|
||||||
// 容错值
|
// 容错值
|
||||||
Float tolerant = imageCaptchaInfo.getTolerant();
|
Float tolerant = imageCaptchaInfo.getTolerant();
|
||||||
if (tolerant != null && tolerant > 0) {
|
if (tolerant != null && tolerant > 0) {
|
||||||
@@ -77,13 +87,17 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
type = CaptchaTypeConstant.SLIDER;
|
type = CaptchaTypeConstant.SLIDER;
|
||||||
}
|
}
|
||||||
map.put(TYPE_KEY, type);
|
map.put(TYPE_KEY, type);
|
||||||
|
return true;
|
||||||
return afterGenerateImageCaptchaValidData(map, imageCaptchaInfo, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> afterGenerateImageCaptchaValidData(Map<String, Object> map,
|
public void afterGenerateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo, Map<String, Object> map) {
|
||||||
ImageCaptchaInfo imageCaptchaInfo,
|
|
||||||
String type) {
|
}
|
||||||
|
|
||||||
|
public void doGenerateImageCaptchaValidData(Map<String, Object> map,
|
||||||
|
ImageCaptchaInfo imageCaptchaInfo) {
|
||||||
|
// type
|
||||||
|
String type = (String) map.getOrDefault(TYPE_KEY, CaptchaTypeConstant.SLIDER);
|
||||||
if (CaptchaUtils.isSliderCaptcha(type)) {
|
if (CaptchaUtils.isSliderCaptcha(type)) {
|
||||||
// 滑动验证码
|
// 滑动验证码
|
||||||
addPercentage(imageCaptchaInfo, map);
|
addPercentage(imageCaptchaInfo, map);
|
||||||
@@ -93,7 +107,7 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
if (expand == null) {
|
if (expand == null) {
|
||||||
throw new IllegalArgumentException("点选验证码扩展数据转换为 List<ClickImageCheckDefinition> 失败, info=" + imageCaptchaInfo);
|
throw new IllegalArgumentException("点选验证码扩展数据转换为 List<ClickImageCheckDefinition> 失败, info=" + imageCaptchaInfo);
|
||||||
}
|
}
|
||||||
List<ClickImageCheckDefinition> clickImageCheckDefinitionList = null;
|
List<ClickImageCheckDefinition> clickImageCheckDefinitionList;
|
||||||
try {
|
try {
|
||||||
clickImageCheckDefinitionList = (List<ClickImageCheckDefinition>) expand;
|
clickImageCheckDefinitionList = (List<ClickImageCheckDefinition>) expand;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -116,17 +130,15 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
map.put(TOLERANT_KEY, tolerant);
|
map.put(TOLERANT_KEY, tolerant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 添加点选验证
|
// 添加点选验证数据
|
||||||
map.put(PERCENTAGE_KEY, sb.toString());
|
map.put(PERCENTAGE_KEY, sb.toString());
|
||||||
}
|
}
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
public boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
||||||
|
|
||||||
// 读容错值
|
// 读容错值
|
||||||
Float tolerantData = getFloatParam(TOLERANT_KEY, sliderCaptchaValidData, defaultTolerant);
|
Float tolerant = getFloatParam(TOLERANT_KEY, sliderCaptchaValidData, defaultTolerant);
|
||||||
// 读验证码类型
|
// 读验证码类型
|
||||||
String type = getStringParam(TYPE_KEY, sliderCaptchaValidData, CaptchaTypeConstant.SLIDER);
|
String type = getStringParam(TYPE_KEY, sliderCaptchaValidData, CaptchaTypeConstant.SLIDER);
|
||||||
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
|
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
|
||||||
@@ -139,10 +151,46 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
// 没有滑动轨迹
|
// 没有滑动轨迹
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return afterValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerantData, type);
|
// 验证前
|
||||||
|
if (!beforeValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 验证
|
||||||
|
boolean valid = doValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||||
|
if (valid) {
|
||||||
|
// 验证后
|
||||||
|
valid = afterValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean afterValid(SliderCaptchaTrack sliderCaptchaTrack,
|
/**
|
||||||
|
* 验证前
|
||||||
|
*
|
||||||
|
* @param sliderCaptchaTrack sliderCaptchaTrack
|
||||||
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
|
* @param tolerant tolerant
|
||||||
|
* @param type type
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean beforeValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证后
|
||||||
|
*
|
||||||
|
* @param sliderCaptchaTrack sliderCaptchaTrack
|
||||||
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
|
* @param tolerant tolerant
|
||||||
|
* @param type type
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean afterValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean doValid(SliderCaptchaTrack sliderCaptchaTrack,
|
||||||
Map<String, Object> sliderCaptchaValidData,
|
Map<String, Object> sliderCaptchaValidData,
|
||||||
Float tolerant,
|
Float tolerant,
|
||||||
String type) {
|
String type) {
|
||||||
@@ -160,6 +208,7 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验点选验证码
|
* 校验点选验证码
|
||||||
|
*
|
||||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
* @param sliderCaptchaTrack sliderCaptchaTrack
|
||||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
* @param tolerant tolerant
|
* @param tolerant tolerant
|
||||||
@@ -176,18 +225,26 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
}
|
}
|
||||||
String[] splitArr = validStr.split(";");
|
String[] splitArr = validStr.split(";");
|
||||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
||||||
if (trackList.size() != splitArr.length) {
|
if (trackList.size() < splitArr.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 取出点击事件的轨迹数据
|
||||||
|
List<SliderCaptchaTrack.Track> clickTrackList = trackList
|
||||||
|
.stream()
|
||||||
|
.filter(t -> TrackTypeConstant.CLICK.equalsIgnoreCase(t.getType()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (clickTrackList.size() != splitArr.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < splitArr.length; i++) {
|
for (int i = 0; i < splitArr.length; i++) {
|
||||||
SliderCaptchaTrack.Track track = trackList.get(i);
|
SliderCaptchaTrack.Track track = clickTrackList.get(i);
|
||||||
String posStr = splitArr[i];
|
String posStr = splitArr[i];
|
||||||
String[] posArr = posStr.split(",");
|
String[] posArr = posStr.split(",");
|
||||||
float xPercentage = Float.parseFloat(posArr[0]);
|
float xPercentage = Float.parseFloat(posArr[0]);
|
||||||
float yPercentage = Float.parseFloat(posArr[1]);
|
float yPercentage = Float.parseFloat(posArr[1]);
|
||||||
|
|
||||||
float calcXPercentage = calcPercentage(track.getX(), sliderCaptchaTrack.getBgImageWidth());
|
float calcXPercentage = calcPercentage(track.getX(), sliderCaptchaTrack.getBgImageWidth());
|
||||||
float calcYPercentage = calcPercentage(track.getY(), sliderCaptchaTrack.getBgImageWidth());
|
float calcYPercentage = calcPercentage(track.getY(), sliderCaptchaTrack.getBgImageHeight());
|
||||||
|
|
||||||
if (!checkPercentage(calcXPercentage, xPercentage, tolerant)
|
if (!checkPercentage(calcXPercentage, xPercentage, tolerant)
|
||||||
|| !checkPercentage(calcYPercentage, yPercentage, tolerant)) {
|
|| !checkPercentage(calcYPercentage, yPercentage, tolerant)) {
|
||||||
@@ -199,6 +256,7 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验滑动验证码
|
* 校验滑动验证码
|
||||||
|
*
|
||||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
* @param sliderCaptchaTrack sliderCaptchaTrack
|
||||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
* @param tolerant tolerant
|
* @param tolerant tolerant
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package example;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.RotateImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.impl.CacheImageCaptchaGenerator;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.impl.StandardConcatImageCaptchaGenerator;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.impl.StandardRotateImageCaptchaGenerator;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.impl.DefaultImageCaptchaResourceManager;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.impl.DefaultResourceStore;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class StandardConcatCaptchaGeneratorTest {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
ResourceStore resourceStore = new DefaultResourceStore();
|
||||||
|
// Map<String, Resource> template = new HashMap<>();
|
||||||
|
// template.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource("file", "C:\\Users\\Thinkpad\\Desktop\\a.png"));
|
||||||
|
// template.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource("file", "C:\\Users\\Thinkpad\\Desktop\\b.png"));
|
||||||
|
|
||||||
|
// resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template);
|
||||||
|
// resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource("file", "E:\\projects\\tianai-captcha\\src\\main\\resources\\META-INF\\cut-image\\resource\\1.jpg"));
|
||||||
|
|
||||||
|
ImageCaptchaResourceManager imageCaptchaResourceManager = new DefaultImageCaptchaResourceManager(resourceStore);
|
||||||
|
|
||||||
|
StandardConcatImageCaptchaGenerator captchaGenerator = new StandardConcatImageCaptchaGenerator(imageCaptchaResourceManager, true);
|
||||||
|
ImageCaptchaInfo imageCaptchaInfo = captchaGenerator.generateCaptchaImage(CaptchaTypeConstant.CONCAT);
|
||||||
|
System.out.println("backgroundImage:" + imageCaptchaInfo.getBackgroundImage());
|
||||||
|
System.out.println("sliderImage:" + imageCaptchaInfo.getSliderImage());
|
||||||
|
|
||||||
|
TimeUnit.DAYS.sleep(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ public class StandardWordClickImageCaptchaGeneratorTest {
|
|||||||
new StandardRandomWordClickImageCaptchaGenerator(imageCaptchaResourceManager, true);
|
new StandardRandomWordClickImageCaptchaGenerator(imageCaptchaResourceManager, true);
|
||||||
|
|
||||||
GenerateParam generateParam = new GenerateParam();
|
GenerateParam generateParam = new GenerateParam();
|
||||||
generateParam.setType(CaptchaTypeConstant.IMAGE_CLICK);
|
generateParam.setType(CaptchaTypeConstant.WORD_IMAGE_CLICK);
|
||||||
generateParam.setSliderFormatName("png");
|
generateParam.setSliderFormatName("png");
|
||||||
ImageCaptchaInfo imageCaptchaInfo = defaultImageCaptchaResourceManager.generateCaptchaImage(generateParam);
|
ImageCaptchaInfo imageCaptchaInfo = defaultImageCaptchaResourceManager.generateCaptchaImage(generateParam);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user