From 3b1b211629c47ad0cb27409a9192b6277eb02919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A9=E7=88=B1=E6=9C=89=E6=83=85?= Date: Wed, 12 Mar 2025 17:35:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(captcha):=20=E4=BC=98=E5=8C=96=E7=82=B9?= =?UTF-8?q?=E9=80=89=E9=AA=8C=E8=AF=81=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 AbstractClickImageCaptchaGenerator 中的 getClickImg 方法,增加 randomColor 参数 - 更新 MultiImageCaptchaGenerator 中的 StandardWordClickImageCaptchaGenerator 实例创建方式 - 新增 ParamKeyEnum 类,用于定义点选验证码的参数键 - 更新 StandardWordClickImageCaptchaGenerator 中的随机字体选择逻辑 -调整 filterAndSortClickImageCheckDefinition 方法,支持自定义校验数量 --- pom.xml | 2 +- .../common/model/dto/ParamKeyEnum.java | 19 ++++++ .../AbstractClickImageCaptchaGenerator.java | 8 +-- .../impl/MultiImageCaptchaGenerator.java | 11 ++- ...tandardWordClickImageCaptchaGenerator.java | 68 +++++++++++-------- 5 files changed, 69 insertions(+), 39 deletions(-) create mode 100644 src/main/java/cloud/tianai/captcha/generator/common/model/dto/ParamKeyEnum.java diff --git a/pom.xml b/pom.xml index 9d19e20..ab79290 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 cloud.tianai.captcha tianai-captcha - 1.5.1 + 1.5.2 tianai-captcha 行为验证码 diff --git a/src/main/java/cloud/tianai/captcha/generator/common/model/dto/ParamKeyEnum.java b/src/main/java/cloud/tianai/captcha/generator/common/model/dto/ParamKeyEnum.java new file mode 100644 index 0000000..937afb8 --- /dev/null +++ b/src/main/java/cloud/tianai/captcha/generator/common/model/dto/ParamKeyEnum.java @@ -0,0 +1,19 @@ +package cloud.tianai.captcha.generator.common.model.dto; + + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ParamKeyEnum implements ParamKey { + + + /** 点选验证码参与校验的数量. 值为Integer */ + public static final ParamKey CLICK_CHECK_CLICK_COUNT = new ParamKeyEnum<>("checkClickCount"); + /** 点选验证码干扰数量. 值为Integer */ + public static final ParamKey CLICK_INTERFERENCE_COUNT = new ParamKeyEnum<>("interferenceCount"); + + private String key; + +} diff --git a/src/main/java/cloud/tianai/captcha/generator/impl/AbstractClickImageCaptchaGenerator.java b/src/main/java/cloud/tianai/captcha/generator/impl/AbstractClickImageCaptchaGenerator.java index 7c0e0f8..91494d2 100644 --- a/src/main/java/cloud/tianai/captcha/generator/impl/AbstractClickImageCaptchaGenerator.java +++ b/src/main/java/cloud/tianai/captcha/generator/impl/AbstractClickImageCaptchaGenerator.java @@ -51,7 +51,7 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa } for (int i = 0; i < allImages; i++) { // 随机获取点击图片 - ImgWrapper imgWrapper = getClickImg(imgTips.get(i)); + ImgWrapper imgWrapper = getClickImg(imgTips.get(i),null); BufferedImage image = imgWrapper.getImage(); int clickImgWidth = image.getWidth(); int clickImgHeight = image.getHeight(); @@ -75,7 +75,7 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa clickImageCheckDefinition.setImageColor(imgWrapper.getImageColor()); clickImageCheckDefinitionList.add(clickImageCheckDefinition); } - List checkClickImageCheckDefinitionList = filterAndSortClickImageCheckDefinition(clickImageCheckDefinitionList); + List checkClickImageCheckDefinitionList = filterAndSortClickImageCheckDefinition(captchaExchange,clickImageCheckDefinitionList); captchaExchange.setBackgroundImage(bgImage); captchaExchange.setTransferData(checkClickImageCheckDefinitionList); captchaExchange.setResourceImage(resourceImage); @@ -94,7 +94,7 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa * @param allCheckDefinitionList 总的点选图片 * @return List */ - protected abstract List filterAndSortClickImageCheckDefinition(List allCheckDefinitionList); + protected abstract List filterAndSortClickImageCheckDefinition(CaptchaExchange captchaExchange,List allCheckDefinitionList); /** * 随机获取一组数据用于生成随机图 @@ -109,7 +109,7 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa * @param tip 提示数据,根据改数据生成图片 * @return ImgWrapper */ - public abstract ImgWrapper getClickImg(Resource tip); + public abstract ImgWrapper getClickImg(Resource tip, Color randomColor); /** * @Author: 天爱有情 diff --git a/src/main/java/cloud/tianai/captcha/generator/impl/MultiImageCaptchaGenerator.java b/src/main/java/cloud/tianai/captcha/generator/impl/MultiImageCaptchaGenerator.java index c3e992c..3e674a7 100644 --- a/src/main/java/cloud/tianai/captcha/generator/impl/MultiImageCaptchaGenerator.java +++ b/src/main/java/cloud/tianai/captcha/generator/impl/MultiImageCaptchaGenerator.java @@ -5,7 +5,6 @@ import cloud.tianai.captcha.generator.AbstractImageCaptchaGenerator; import cloud.tianai.captcha.generator.ImageCaptchaGenerator; import cloud.tianai.captcha.generator.ImageCaptchaGeneratorProvider; import cloud.tianai.captcha.generator.ImageTransform; -import cloud.tianai.captcha.generator.common.FontWrapper; import cloud.tianai.captcha.generator.common.model.dto.CaptchaExchange; import cloud.tianai.captcha.generator.common.model.dto.GenerateParam; import cloud.tianai.captcha.generator.common.model.dto.ImageCaptchaInfo; @@ -15,7 +14,6 @@ import lombok.Getter; import lombok.Setter; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -31,9 +29,9 @@ public class MultiImageCaptchaGenerator extends AbstractImageCaptchaGenerator { protected Map imageCaptchaGeneratorMap = new ConcurrentHashMap<>(4); protected Map imageCaptchaGeneratorProviderMap = new HashMap<>(4); // 点选类验证码字体 - @Setter - @Getter - protected List fontWrappers; +// @Setter +// @Getter +// protected List fontWrappers; @Setter @Getter private String defaultCaptcha = SLIDER; @@ -56,8 +54,7 @@ public class MultiImageCaptchaGenerator extends AbstractImageCaptchaGenerator { // 拼接验证码 addImageCaptchaGeneratorProvider(new CommonImageCaptchaGeneratorProvider(CONCAT, StandardConcatImageCaptchaGenerator::new)); // 点选文字验证码 - addImageCaptchaGeneratorProvider(new CommonImageCaptchaGeneratorProvider(WORD_IMAGE_CLICK, (r, t, i) -> - new StandardWordClickImageCaptchaGenerator(r, t, i, fontWrappers))); + addImageCaptchaGeneratorProvider(new CommonImageCaptchaGeneratorProvider(WORD_IMAGE_CLICK, StandardWordClickImageCaptchaGenerator::new)); } public void addImageCaptchaGeneratorProvider(ImageCaptchaGeneratorProvider provider) { diff --git a/src/main/java/cloud/tianai/captcha/generator/impl/StandardWordClickImageCaptchaGenerator.java b/src/main/java/cloud/tianai/captcha/generator/impl/StandardWordClickImageCaptchaGenerator.java index 9cbc881..6629b6e 100644 --- a/src/main/java/cloud/tianai/captcha/generator/impl/StandardWordClickImageCaptchaGenerator.java +++ b/src/main/java/cloud/tianai/captcha/generator/impl/StandardWordClickImageCaptchaGenerator.java @@ -1,14 +1,15 @@ package cloud.tianai.captcha.generator.impl; import cloud.tianai.captcha.common.constant.CaptchaTypeConstant; +import cloud.tianai.captcha.common.constant.CommonConstant; import cloud.tianai.captcha.common.exception.ImageCaptchaException; -import cloud.tianai.captcha.common.util.CollectionUtils; import cloud.tianai.captcha.common.util.FontUtils; import cloud.tianai.captcha.generator.ImageTransform; import cloud.tianai.captcha.generator.common.FontWrapper; import cloud.tianai.captcha.generator.common.model.dto.*; import cloud.tianai.captcha.generator.common.util.CaptchaImageUtils; import cloud.tianai.captcha.interceptor.CaptchaInterceptor; +import cloud.tianai.captcha.resource.FontCache; import cloud.tianai.captcha.resource.ImageCaptchaResourceManager; import cloud.tianai.captcha.resource.common.model.dto.Resource; import lombok.Getter; @@ -30,9 +31,9 @@ import java.util.stream.Collectors; public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCaptchaGenerator { /** 字体包. */ - @Getter - @Setter - protected List fonts = new ArrayList<>(); +// @Getter +// @Setter +// protected List fonts = new ArrayList<>(); @Getter @Setter protected Integer clickImgWidth = 100; @@ -64,12 +65,7 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa // // protected float currentFontTopCoef = 0.0f; public StandardWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager) { - super(imageCaptchaResourceManager); - } - - public StandardWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, ImageTransform imageTransform) { - super(imageCaptchaResourceManager); - setImageTransform(imageTransform); + this(imageCaptchaResourceManager, null, null); } @@ -79,16 +75,11 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa setInterceptor(interceptor); } - public StandardWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, ImageTransform imageTransform, CaptchaInterceptor interceptor, List fonts) { - super(imageCaptchaResourceManager); - setImageTransform(imageTransform); - setInterceptor(interceptor); - this.fonts = fonts; - } - @Override protected List randomGetClickImgTips(GenerateParam param) { + Integer checkClickCount = param.getOrDefault(ParamKeyEnum.CLICK_CHECK_CLICK_COUNT, getCheckClickCount()); + Integer interferenceCount = param.getOrDefault(ParamKeyEnum.CLICK_INTERFERENCE_COUNT, getInterferenceCount()); int tipSize = interferenceCount + checkClickCount; ThreadLocalRandom random = ThreadLocalRandom.current(); List tipList = new ArrayList<>(tipSize); @@ -102,14 +93,25 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa @Override protected void doInit() { - if (CollectionUtils.isEmpty(fonts)) { - throw new ImageCaptchaException("初始化文字点选验证码失败,请设置字体包后再调用init()"); - } +// if (CollectionUtils.isEmpty(fonts)) { +// throw new ImageCaptchaException("初始化文字点选验证码失败,请设置字体包后再调用init()"); +// } +// ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore(); +// // 添加一些系统的资源文件 +// resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg"), DEFAULT_TAG)); + } + public FontWrapper randomFont() { + Resource resource = requiredRandomGetResource(FontCache.FONT_TYPE, CommonConstant.DEFAULT_TAG); + Object extra = resource.getExtra(); + if (extra instanceof FontWrapper) { + return (FontWrapper) extra; + } + throw new ImageCaptchaException("随机获取字体失败, resource中没有读到字体包, resource=" + resource); } public ImgWrapper genTipImage(List imageCheckDefinitions) { - FontWrapper fontWrapper = fonts.get(randomInt(fonts.size())); + FontWrapper fontWrapper = randomFont(); Font font = fontWrapper.getFont(); float currentFontTopCoef = fontWrapper.getCurrentFontTopCoef(); String tips = imageCheckDefinitions.stream().map(c -> c.getTip().getData()).collect(Collectors.joining()); @@ -124,14 +126,24 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa return new ImgWrapper(bufferedImage, new Resource(null, tips), null); } +// @Override +// public ImgWrapper getClickImg(Resource tip) { +// ThreadLocalRandom random = ThreadLocalRandom.current(); +// // 随机颜色 +// Color randomColor = CaptchaImageUtils.getRandomColor(random); +// return getClickImg(tip, randomColor); +// } + + @Override - public ImgWrapper getClickImg(Resource tip) { - ThreadLocalRandom random = ThreadLocalRandom.current(); - // 随机颜色 - Color randomColor = CaptchaImageUtils.getRandomColor(random); + public ImgWrapper getClickImg(Resource tip, Color randomColor) { + if (randomColor == null) { + ThreadLocalRandom random = ThreadLocalRandom.current(); + randomColor = CaptchaImageUtils.getRandomColor(random); + } // 随机角度 int randomDeg = randomInt(0, 85); - FontWrapper fontWrapper = fonts.get(randomInt(fonts.size())); + FontWrapper fontWrapper = randomFont(); Font font = fontWrapper.getFont(); float currentFontTopCoef = fontWrapper.getCurrentFontTopCoef(); BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor, @@ -145,7 +157,9 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa } @Override - protected List filterAndSortClickImageCheckDefinition(List allCheckDefinitionList) { + protected List filterAndSortClickImageCheckDefinition(CaptchaExchange captchaExchange,List allCheckDefinitionList) { + GenerateParam param = captchaExchange.getParam(); + Integer checkClickCount = param.getOrDefault(ParamKeyEnum.CLICK_CHECK_CLICK_COUNT, getCheckClickCount()); // 打乱 Collections.shuffle(allCheckDefinitionList); // 拿出参与校验的数据