mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
优化
This commit is contained in:
@@ -306,4 +306,15 @@ public class CaptchaImageUtils {
|
||||
}
|
||||
return newImage;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
char randomChar = getRandomChar();
|
||||
System.out.println(randomChar);
|
||||
}
|
||||
|
||||
public static char getRandomChar() {
|
||||
return (char)(0x4e00 + (int)(Math.random()*(0x9fa5 - 0x4e00 + 1)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package cloud.tianai.captcha.template.slider.common.util;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/27 11:34
|
||||
* @Description 字体工具包
|
||||
*/
|
||||
public class FontUtils {
|
||||
|
||||
public static char getRandomChar() {
|
||||
return (char)(0x4e00 + (int)(Math.random()*(0x9fa5 - 0x4e00 + 1)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+2
-1
@@ -56,7 +56,8 @@ public abstract class AbstractImageCaptchaGenerator implements ImageCaptchaGener
|
||||
* @param formatType 格式化类型
|
||||
* @return String
|
||||
*/
|
||||
public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
|
||||
@SneakyThrows(IOException.class)
|
||||
public String transform(BufferedImage bufferedImage, String formatType) {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, formatType, byteArrayOutputStream);
|
||||
//转换成字节码
|
||||
|
||||
+2
@@ -13,4 +13,6 @@ public interface CaptchaTypeConstant {
|
||||
String ROTATE = "ROTATE";
|
||||
/** 拼接.*/
|
||||
String CONCAT = "CONCAT";
|
||||
/** 文字点选.*/
|
||||
String WORD_CLICK = "WORD_CLICK";
|
||||
}
|
||||
|
||||
+11
-4
@@ -30,8 +30,12 @@ public class ImageCaptchaInfo {
|
||||
private Integer sliderImageWidth;
|
||||
/** 滑块图片高度. */
|
||||
private Integer sliderImageHeight;
|
||||
/** 随机值.*/
|
||||
/** 随机值. */
|
||||
private Integer randomX;
|
||||
/** 容错值, 可以为空 默认 0.02容错,校验的时候用. */
|
||||
private Float tolerant;
|
||||
/** 验证码类型.*/
|
||||
private String type;
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
@@ -43,7 +47,8 @@ public class ImageCaptchaInfo {
|
||||
Integer bgImageHeight,
|
||||
Integer sliderImageWidth,
|
||||
Integer sliderImageHeight,
|
||||
Integer randomX) {
|
||||
Integer randomX,
|
||||
String type) {
|
||||
this.backgroundImage = backgroundImage;
|
||||
this.sliderImage = sliderImage;
|
||||
this.bgImageWidth = bgImageWidth;
|
||||
@@ -51,6 +56,7 @@ public class ImageCaptchaInfo {
|
||||
this.sliderImageWidth = sliderImageWidth;
|
||||
this.sliderImageHeight = sliderImageHeight;
|
||||
this.randomX = randomX;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static ImageCaptchaInfo of(String backgroundImage,
|
||||
@@ -59,8 +65,9 @@ public class ImageCaptchaInfo {
|
||||
Integer bgImageHeight,
|
||||
Integer sliderImageWidth,
|
||||
Integer sliderImageHeight,
|
||||
Integer randomKey) {
|
||||
return new ImageCaptchaInfo( backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight, randomKey);
|
||||
Integer randomKey,
|
||||
String type) {
|
||||
return new ImageCaptchaInfo(backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight, randomKey, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,5 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
@@ -17,8 +18,8 @@ public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
|
||||
* 旋转多少度
|
||||
*/
|
||||
private Double degree;
|
||||
|
||||
|
||||
/** 旋转图片的容错值大一点. */
|
||||
public static final Float DEFAULT_TOLERANT = 0.05F;
|
||||
|
||||
public static RotateImageCaptchaInfo of(Double degree,
|
||||
Integer randomX,
|
||||
@@ -32,11 +33,14 @@ public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
|
||||
rotateImageCaptchaInfo.setDegree(degree);
|
||||
rotateImageCaptchaInfo.setRandomX(randomX);
|
||||
rotateImageCaptchaInfo.setBackgroundImage(backgroundImage);
|
||||
rotateImageCaptchaInfo.setTolerant(DEFAULT_TOLERANT);
|
||||
rotateImageCaptchaInfo.setSliderImage(sliderImage);
|
||||
rotateImageCaptchaInfo.setBgImageWidth(bgImageWidth);
|
||||
rotateImageCaptchaInfo.setBgImageHeight(bgImageHeight);
|
||||
rotateImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
|
||||
rotateImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
|
||||
// 类型为旋转图片验证码
|
||||
rotateImageCaptchaInfo.setType(CaptchaTypeConstant.ROTATE);
|
||||
return rotateImageCaptchaInfo;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
@@ -36,7 +37,7 @@ public class SliderImageCaptchaInfo extends ImageCaptchaInfo {
|
||||
sliderImageCaptchaInfo.setBgImageHeight(bgImageHeight);
|
||||
sliderImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
|
||||
sliderImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
|
||||
|
||||
sliderImageCaptchaInfo.setType(CaptchaTypeConstant.SLIDER);
|
||||
return sliderImageCaptchaInfo;
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/27 15:33
|
||||
* @Description 文字点选
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class WordClickImageCaptchaInfo extends ImageCaptchaInfo {
|
||||
|
||||
private List<WordDefinition> checkWords;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class WordDefinition {
|
||||
private String word;
|
||||
private Integer x;
|
||||
private Integer y;
|
||||
private Integer deg;
|
||||
private Integer wordWidth;
|
||||
private Integer wordHeight;
|
||||
|
||||
}
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils;
|
||||
import cloud.tianai.captcha.template.slider.common.util.FontUtils;
|
||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
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.WordClickImageCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
||||
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.impl.provider.ClassPathResourceProvider;
|
||||
import cloud.tianai.captcha.template.slider.resource.impl.provider.FileResourceProvider;
|
||||
import lombok.Data;
|
||||
import lombok.SneakyThrows;
|
||||
import sun.font.FontDesignMetrics;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.wrapFile2BufferedImage;
|
||||
import static cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/27 11:46
|
||||
* @Description 点选验证码
|
||||
*/
|
||||
@Data
|
||||
public class StandardClickImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||
|
||||
|
||||
protected ImageCaptchaResourceManager imageCaptchaResourceManager;
|
||||
|
||||
protected Integer checkFontCount = 4;
|
||||
protected Integer interferenceCount = checkFontCount + 2;
|
||||
protected Font font;
|
||||
protected List<Color> randomColors = Arrays.asList(Color.PINK, Color.BLUE, Color.GREEN, Color.BLACK);
|
||||
|
||||
@SneakyThrows
|
||||
public StandardClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
|
||||
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
Resource fontResource = new Resource("", "META-INF/fonts/SIMSUN.TTC");
|
||||
InputStream inputStream = new ClassPathResourceProvider().doGetResourceInputStream(fontResource);
|
||||
this.font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
|
||||
this.font = font.deriveFont(Font.BOLD, 50);
|
||||
}
|
||||
|
||||
public StandardClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager,
|
||||
boolean initDefaultResource,
|
||||
Font font) {
|
||||
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
|
||||
this.font = font;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void initDefaultResource() {
|
||||
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
|
||||
// 添加一些系统的资源文件
|
||||
resourceStore.addResource(CaptchaTypeConstant.WORD_CLICK, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||
|
||||
// 文字点选验证码不需要模板 只需要背景图
|
||||
Collection<InputStream> inputStreams = new LinkedList<>();
|
||||
try {
|
||||
Resource resourceImage = imageCaptchaResourceManager.randomGetResource(param.getType());
|
||||
InputStream resourceInputStream = imageCaptchaResourceManager.getResourceInputStream(resourceImage);
|
||||
inputStreams.add(resourceInputStream);
|
||||
BufferedImage bgImage = wrapFile2BufferedImage(resourceInputStream);
|
||||
Graphics2D graphics = (Graphics2D) bgImage.getGraphics();
|
||||
|
||||
List<WordClickImageCaptchaInfo.WordDefinition> wordDefinitionList = new ArrayList<>(interferenceCount);
|
||||
for (int i = 0; i < interferenceCount; i++) {
|
||||
// 随机角度
|
||||
|
||||
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
|
||||
// 随机文字
|
||||
String randomWord = String.valueOf(FontUtils.getRandomChar());
|
||||
int wordWidth = metrics.stringWidth(randomWord);
|
||||
int wordHeight = metrics.getHeight();
|
||||
// 随机颜色
|
||||
Color randomColor = randomColor();
|
||||
// 随机x
|
||||
int randomX = ThreadLocalRandom.current().nextInt(10, bgImage.getWidth() - wordWidth);
|
||||
// 随机y
|
||||
int randomY = ThreadLocalRandom.current().nextInt(10, bgImage.getHeight() - wordHeight);
|
||||
int randomDeg = ThreadLocalRandom.current().nextInt(0, 85);
|
||||
AffineTransform affineTransform = new AffineTransform();
|
||||
affineTransform.rotate(Math.toRadians(randomDeg));
|
||||
Font rotatedFont = font.deriveFont(affineTransform);
|
||||
graphics.setFont(rotatedFont);
|
||||
graphics.setColor(randomColor);
|
||||
graphics.drawString(randomWord, randomX, randomY + metrics.getAscent());
|
||||
|
||||
WordClickImageCaptchaInfo.WordDefinition wordDefinition = new WordClickImageCaptchaInfo.WordDefinition();
|
||||
wordDefinition.setWord(randomWord);
|
||||
wordDefinition.setX(randomX + wordWidth / 2);
|
||||
wordDefinition.setY(randomY + wordHeight / 2);
|
||||
wordDefinition.setDeg(randomDeg);
|
||||
wordDefinition.setWordWidth(wordWidth);
|
||||
wordDefinition.setWordHeight(wordHeight);
|
||||
wordDefinitionList.add(wordDefinition);
|
||||
}
|
||||
// 背景图转换为字符串
|
||||
// String bgImageStr = transform(bgImage, param.getBackgroundFormatName());
|
||||
try {
|
||||
ImageIO.write(bgImage, "jpeg", new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\123.jpg"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 打乱 word
|
||||
Collections.shuffle(wordDefinitionList);
|
||||
// 拿出要校验的文字
|
||||
List<WordClickImageCaptchaInfo.WordDefinition> checkWordDefinitionList = new ArrayList<>(checkFontCount);
|
||||
for (int i = 0; i < checkFontCount; i++) {
|
||||
checkWordDefinitionList.add(wordDefinitionList.get(i));
|
||||
}
|
||||
|
||||
System.out.println(checkWordDefinitionList);
|
||||
return null;
|
||||
|
||||
} finally {
|
||||
// 使用完后关闭流
|
||||
for (InputStream inputStream : inputStreams) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return null;
|
||||
}
|
||||
|
||||
protected Color randomColor() {
|
||||
if (randomColors.size() == 1) {
|
||||
return randomColors.get(0);
|
||||
}
|
||||
return randomColors.get(ThreadLocalRandom.current().nextInt(0, randomColors.size() - 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageCaptchaResourceManager getImageResourceManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws IOException, FontFormatException {
|
||||
Resource fontResource = new Resource("", "META-INF/fonts/SIMSUN.TTC");
|
||||
InputStream inputStream = new ClassPathResourceProvider().doGetResourceInputStream(fontResource);
|
||||
Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
|
||||
font = font.deriveFont(Font.BOLD, 100);
|
||||
|
||||
|
||||
for (int i = 40; i < 60; i+=1) {
|
||||
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
|
||||
|
||||
Resource imageResource = new Resource("", "C:\\Users\\Thinkpad\\Desktop\\111.jpg");
|
||||
inputStream = new FileResourceProvider().doGetResourceInputStream(imageResource);
|
||||
BufferedImage bufferedImage = CaptchaImageUtils.wrapFile2BufferedImage(inputStream);
|
||||
|
||||
Graphics graphics = bufferedImage.getGraphics();
|
||||
graphics.setColor(Color.PINK);
|
||||
//设置角度
|
||||
AffineTransform affineTransform = new AffineTransform();
|
||||
affineTransform.rotate(Math.toRadians(180), i , -i);
|
||||
Font rotatedFont = font.deriveFont(affineTransform);
|
||||
graphics.setFont(rotatedFont);
|
||||
char ch = FontUtils.getRandomChar();
|
||||
// graphics.drawString(String.valueOf(ch), 10, 10+metrics.getAscent());
|
||||
// graphics.drawString(String.valueOf(ch), 50, 50);
|
||||
String randomWord = "张"/*String.valueOf(FontUtils.getRandomChar())*/;
|
||||
int wordWidth = metrics.stringWidth(randomWord);
|
||||
int wordHeight = metrics.getHeight();
|
||||
// //左边位置
|
||||
int left = (bufferedImage.getWidth()-wordWidth)/2;
|
||||
// //顶边位置+上升距离(原本字体基线位置对准画布的y坐标导致字体偏上ascent距离,加上ascent后下移刚好顶边吻合)
|
||||
int top = (bufferedImage.getHeight()-wordHeight)/2+metrics.getAscent();
|
||||
|
||||
// 随机生成6个字的居中的 x 和 y
|
||||
// for (int i = 0; i < 6; i++) {
|
||||
|
||||
|
||||
// int randomX = ThreadLocalRandom.current().nextInt(10, bufferedImage.getWidth() - wordWidth);
|
||||
// int randomY = ThreadLocalRandom.current().nextInt(10, bufferedImage.getHeight() - wordHeight);
|
||||
|
||||
graphics.drawString(randomWord, left, top);
|
||||
|
||||
System.out.println(randomWord + "-->x:" + (left + wordWidth / 2) + ",y:" + (left + wordHeight / 2));
|
||||
// }
|
||||
|
||||
// graphics.drawString("居中文字",0,metrics.getAscent()); //基线对齐改为顶边对齐
|
||||
ImageIO.write(bufferedImage, "jpeg", new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\111\\"+i+".jpg"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -27,7 +27,7 @@ import static cloud.tianai.captcha.template.slider.generator.impl.StandardSlider
|
||||
*/
|
||||
public class StandardConcatImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||
|
||||
protected final ImageCaptchaResourceManager imageCaptchaResourceManager;
|
||||
protected ImageCaptchaResourceManager imageCaptchaResourceManager;
|
||||
|
||||
public StandardConcatImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
|
||||
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
|
||||
@@ -79,7 +79,16 @@ public class StandardConcatImageCaptchaGenerator extends AbstractImageCaptchaGen
|
||||
private ImageCaptchaInfo wrapConcatCaptchaInfo(int randomX, BufferedImage bgImage, BufferedImage sliderImage, GenerateParam param) {
|
||||
String backGroundImageBase64 = transform(bgImage, param.getBackgroundFormatName());
|
||||
String sliderImageBase64 = transform(sliderImage, param.getSliderFormatName());
|
||||
return ImageCaptchaInfo.of(backGroundImageBase64, sliderImageBase64, bgImage.getWidth(), bgImage.getHeight(), sliderImage.getWidth(), sliderImage.getHeight(), randomX);
|
||||
ImageCaptchaInfo imageCaptchaInfo = ImageCaptchaInfo.of(backGroundImageBase64,
|
||||
sliderImageBase64,
|
||||
bgImage.getWidth(),
|
||||
bgImage.getHeight(),
|
||||
sliderImage.getWidth(),
|
||||
sliderImage.getHeight(),
|
||||
randomX,
|
||||
CaptchaTypeConstant.CONCAT);
|
||||
imageCaptchaInfo.setTolerant(0.05F);
|
||||
return imageCaptchaInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+79
-22
@@ -1,6 +1,8 @@
|
||||
package cloud.tianai.captcha.template.slider.validator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
||||
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
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.common.model.dto.SliderCaptchaTrack;
|
||||
@@ -26,6 +28,10 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||
@Setter
|
||||
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() {
|
||||
}
|
||||
|
||||
@@ -59,16 +65,28 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||
public Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
||||
Map<String, Object> map = new HashMap<>(8);
|
||||
addPercentage(imageCaptchaInfo, map);
|
||||
// 容错值
|
||||
Float tolerant = imageCaptchaInfo.getTolerant();
|
||||
if (tolerant != null && tolerant > 0) {
|
||||
map.put(TOLERANT_KEY, tolerant);
|
||||
}
|
||||
// 类型
|
||||
String type = imageCaptchaInfo.getType();
|
||||
if (ObjectUtils.isEmpty(type)) {
|
||||
type = CaptchaTypeConstant.SLIDER;
|
||||
}
|
||||
map.put(TYPE_KEY, type);
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
||||
Float oriPercentage = getPercentage(sliderCaptchaTrack, sliderCaptchaValidData);
|
||||
if (oriPercentage == null) {
|
||||
// 没读取到百分比
|
||||
return false;
|
||||
}
|
||||
Float oriPercentage = getFloatParam(PERCENTAGE_KEY, sliderCaptchaValidData);
|
||||
// 读容错值
|
||||
Float tolerantData = getFloatParam(TOLERANT_KEY, sliderCaptchaValidData, defaultTolerant);
|
||||
// 读验证码类型
|
||||
String type = getStringParam(TYPE_KEY, sliderCaptchaValidData, CaptchaTypeConstant.SLIDER);
|
||||
|
||||
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
|
||||
if (bgImageWidth == null || bgImageWidth < 1) {
|
||||
// 没有背景图片宽度
|
||||
@@ -79,35 +97,74 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||
// 没有滑动轨迹
|
||||
return false;
|
||||
}
|
||||
// 取最后一个滑动轨迹
|
||||
SliderCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
|
||||
// 计算百分比
|
||||
float calcPercentage = calcPercentage(lastTrack.getX(), bgImageWidth);
|
||||
// 校验百分比
|
||||
return checkPercentage(calcPercentage, oriPercentage);
|
||||
return doValid(sliderCaptchaTrack, sliderCaptchaValidData, oriPercentage, tolerantData, type);
|
||||
}
|
||||
|
||||
protected Float getPercentage(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
||||
Object percentage = sliderCaptchaValidData.get("percentage");
|
||||
if (percentage != null) {
|
||||
if (percentage instanceof Number) {
|
||||
return ((Number) percentage).floatValue();
|
||||
public boolean doValid(SliderCaptchaTrack sliderCaptchaTrack,
|
||||
Map<String, Object> sliderCaptchaValidData,
|
||||
Float oriPercentage,
|
||||
Float tolerant,
|
||||
String type) {
|
||||
if (CaptchaTypeConstant.SLIDER.equals(type)
|
||||
|| CaptchaTypeConstant.ROTATE.equals(type)
|
||||
|| CaptchaTypeConstant.CONCAT.equals(type)) {
|
||||
if (oriPercentage == null) {
|
||||
// 没读取到百分比
|
||||
return false;
|
||||
}
|
||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
||||
// 取最后一个滑动轨迹
|
||||
SliderCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
|
||||
// 计算百分比
|
||||
float calcPercentage = calcPercentage(lastTrack.getX(), sliderCaptchaTrack.getBgImageWidth());
|
||||
// 校验百分比
|
||||
return checkPercentage(calcPercentage, oriPercentage, tolerant);
|
||||
}
|
||||
// 不支持的类型
|
||||
log.warn("校验验证码警告, 不支持的验证码类型:{}, 请手动扩展 cloud.tianai.captcha.template.slider.validator.impl.SimpleImageCaptchaValidator.doValid 进行校验扩展", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Float getFloatParam(String key, Map<String, Object> sliderCaptchaValidData) {
|
||||
return getFloatParam(key, sliderCaptchaValidData, null);
|
||||
}
|
||||
|
||||
protected Float getFloatParam(String key, Map<String, Object> sliderCaptchaValidData, Float defaultData) {
|
||||
Object data = sliderCaptchaValidData.get(key);
|
||||
if (data != null) {
|
||||
if (data instanceof Number) {
|
||||
return ((Number) data).floatValue();
|
||||
}
|
||||
try {
|
||||
if (percentage instanceof String) {
|
||||
return Float.parseFloat((String) percentage);
|
||||
if (data instanceof String) {
|
||||
return Float.parseFloat((String) data);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("从 sliderCaptchaValidData 读取到的 percentage无法转换成float类型, [{}]", percentage);
|
||||
log.error("从 sliderCaptchaValidData 读取到的 " + key + "无法转换成float类型, [{}]", data);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
log.warn("无法从 sliderCaptchaValidData 获取到 percentage");
|
||||
return null;
|
||||
return defaultData;
|
||||
}
|
||||
|
||||
protected String getStringParam(String key, Map<String, Object> sliderCaptchaValidData, String defaultData) {
|
||||
Object data = sliderCaptchaValidData.get(key);
|
||||
if (data != null) {
|
||||
if (data instanceof String) {
|
||||
return (String) data;
|
||||
}
|
||||
try {
|
||||
return String.valueOf(data);
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("从 sliderCaptchaValidData 读取到的 " + key + "无法转换成String类型, [{}]", data);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return defaultData;
|
||||
}
|
||||
|
||||
protected void addPercentage(ImageCaptchaInfo imageCaptchaInfo, Map<String, Object> sliderCaptchaValidData) {
|
||||
float percentage = calcPercentage(imageCaptchaInfo.getRandomX(), imageCaptchaInfo.getBgImageWidth());
|
||||
sliderCaptchaValidData.put("percentage", percentage);
|
||||
sliderCaptchaValidData.put(PERCENTAGE_KEY, percentage);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
package example;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
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.impl.StandardClickImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
||||
import cloud.tianai.captcha.template.slider.resource.impl.DefaultImageCaptchaResourceManager;
|
||||
|
||||
public class StandardWordClickImageCaptchaGeneratorTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ImageCaptchaResourceManager imageCaptchaResourceManager = new DefaultImageCaptchaResourceManager();
|
||||
|
||||
StandardClickImageCaptchaGenerator defaultImageCaptchaResourceManager =
|
||||
new StandardClickImageCaptchaGenerator(imageCaptchaResourceManager, true);
|
||||
|
||||
GenerateParam generateParam = new GenerateParam();
|
||||
generateParam.setType(CaptchaTypeConstant.WORD_CLICK);
|
||||
ImageCaptchaInfo imageCaptchaInfo = defaultImageCaptchaResourceManager.generateCaptchaImage(generateParam);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user