dromara/tianai-captcha 验证码类型详解
本文详细解析了dromara/tianai-captcha中四种验证码的实现原理:滑块验证码、旋转验证码、滑动还原验证码和文字点选验证码。每种验证码类型都包含核心流程、关键代码实现、验证逻辑及安全优化策略,为开发者提供全面的技术参考。
滑块验证码实现原理
滑块验证码是一种常见的行为验证码类型,通过要求用户拖动滑块到指定位置来完成验证。其核心原理包括图像处理、随机位置生成和验证逻辑。以下将详细介绍其实现细节。
1. 核心组件与流程
滑块验证码的实现主要依赖于以下核心组件:
- 背景图与滑块模板:背景图是验证码的底图,滑块模板是用户需要拖动的部分。
- 随机位置生成:系统随机生成滑块在背景图中的目标位置。
- 图像处理:通过切割、叠加等操作生成验证码图像。
- 验证逻辑:校验用户拖动滑块的位置是否在允许的误差范围内。
以下是滑块验证码生成的流程图:
2. 关键代码实现
2.1 随机位置生成
系统通过以下代码生成滑块在背景图中的随机位置:
int randomX = randomInt(fixedTemplate.getWidth() + 5, background.getWidth() - fixedTemplate.getWidth() - 10);
int randomY = randomInt(background.getHeight() - fixedTemplate.getHeight());
randomX和randomY分别表示滑块在背景图中的目标位置。- 通过限制范围确保滑块不会超出背景图边界。
2.2 图像切割与叠加
滑块的生成通过切割背景图并叠加凹槽和混淆块实现:
BufferedImage cutImage = CaptchaImageUtils.cutImage(background, maskTemplate, randomX, randomY);
CaptchaImageUtils.overlayImage(background, fixedTemplate, randomX, randomY);
cutImage是从背景图中切割出的滑块部分。fixedTemplate是凹槽模板,用于在背景图上标记滑块的目标位置。
2.3 混淆块生成
为防止恶意攻击,系统会生成混淆块:
BufferedImage obfuscateImage = createObfuscate(fixedTemplate);
int obfuscateX = randomObfuscateX(randomX, fixedTemplate.getWidth(), background.getWidth());
CaptchaImageUtils.overlayImage(background, obfuscateImage, obfuscateX, randomY);
createObfuscate方法生成一个透明度随机的混淆块。randomObfuscateX确保混淆块不会与滑块重叠。
3. 验证逻辑
用户拖动滑块后,系统会校验其位置是否在允许的误差范围内:
public boolean validate(int userX, int targetX, int tolerance) {
return Math.abs(userX - targetX) <= tolerance;
}
userX是用户拖动滑块的位置。targetX是系统生成的目标位置。tolerance是允许的误差范围。
4. 类图
以下是滑块验证码生成器的类图:
5. 总结
滑块验证码的实现结合了图像处理和随机化技术,确保验证过程既安全又用户友好。通过切割背景图、生成混淆块和严格的验证逻辑,有效防止了自动化攻击。
旋转验证码实现原理
旋转验证码是一种常见的行为验证码类型,其核心原理是通过旋转图片的方式让用户将图片旋转到正确的位置,从而完成验证。本节将深入探讨 dromara/tianai-captcha 中旋转验证码的实现原理,包括生成和校验流程。
1. 旋转验证码生成流程
旋转验证码的生成主要由 StandardRotateImageCaptchaGenerator 类实现。以下是其核心流程:
关键代码分析
public class StandardRotateImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
@Override
public void doGenerateCaptchaImage(CaptchaExchange captchaExchange) {
// 1. 获取背景图片资源
Resource backgroundResource = captchaExchange.getBackgroundResource();
// 2. 随机生成旋转角度
int rotateAngle = generateRandomAngle();
// 3. 旋转图片
BufferedImage rotatedImage = rotateImage(backgroundResource, rotateAngle);
// 4. 存储旋转角度和图片数据
captchaExchange.putCustomData("rotateAngle", rotateAngle);
captchaExchange.putCustomData("rotatedImage", rotatedImage);
}
}
2. 旋转验证码校验流程
旋转验证码的校验由 SimpleImageCaptchaValidator 类实现。以下是其核心流程:
关键代码分析
public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
@Override
public boolean valid(ImageCaptchaTrack track, AnyMap validData) {
// 1. 获取用户提交的旋转角度
int userAngle = track.getParam("rotateAngle");
// 2. 获取正确的旋转角度
int correctAngle = validData.getInt("rotateAngle");
// 3. 计算误差范围
float tolerant = validData.getFloat("tolerant", 5.0f);
// 4. 校验角度是否在允许的误差范围内
return Math.abs(userAngle - correctAngle) <= tolerant;
}
}
3. 核心类与功能
| 类名 | 功能描述 |
|---|---|
StandardRotateImageCaptchaGenerator | 负责生成旋转验证码,包括随机角度生成和图片旋转。 |
SimpleImageCaptchaValidator | 负责校验用户提交的旋转角度是否匹配,支持误差范围配置。 |
ImageCaptchaResourceManager | 管理验证码所需的图片资源,如背景图片和模板图片。 |
4. 示例代码
以下是一个简单的旋转验证码生成和校验示例:
// 生成旋转验证码
ImageCaptchaApplication application = TACBuilder.builder()
.addResource("ROTATE", new Resource("classpath", "background.jpg"))
.build();
CaptchaResponse<ImageCaptchaVO> response = application.generateCaptcha("ROTATE");
// 校验旋转验证码
ImageCaptchaTrack track = new ImageCaptchaTrack();
track.putParam("rotateAngle", 45); // 用户提交的角度
ApiResponse<?> validResponse = application.matching(response.getId(), new MatchParam(track));
System.out.println("校验结果: " + validResponse.isSuccess());
通过以上分析,可以清晰地了解 dromara/tianai-captcha 中旋转验证码的实现原理及其核心流程。
滑动还原验证码实现原理
滑动还原验证码是一种常见的验证码类型,通过要求用户将滑块拖动到指定位置来完成验证。其核心原理包括生成验证码图片、计算滑块位置、验证用户行为等步骤。以下将详细介绍其实现原理。
1. 验证码生成流程
滑动还原验证码的生成流程主要包括以下几个步骤:
- 随机选择背景图片:从资源库中随机选择一张背景图片。
- 随机选择滑块模板:选择滑块和凹槽的模板图片。
- 计算滑块位置:随机生成滑块在背景图片上的位置(x, y坐标)。
- 生成凹槽和滑块:根据模板图片生成凹槽和滑块,并将凹槽嵌入背景图片中。
- 合并图片:将滑块和背景图片合并,生成最终的验证码图片。
- 返回验证码数据:将验证码图片和滑块位置信息返回给前端。
2. 关键代码实现
以下是滑动还原验证码的核心代码实现,基于 StandardSliderImageCaptchaGenerator 类:
@SneakyThrows
@Override
public void doGenerateCaptchaImage(CaptchaExchange captchaExchange) {
GenerateParam param = captchaExchange.getParam();
ResourceMap templateResource = requiredRandomGetTemplate(param.getType(), param.getTemplateImageTag());
Resource resourceImage = requiredRandomGetResource(param.getType(), param.getBackgroundImageTag());
BufferedImage background = getResourceImage(resourceImage);
BufferedImage fixedTemplate = getTemplateImage(templateResource, TEMPLATE_FIXED_IMAGE_NAME);
BufferedImage activeTemplate = getTemplateImage(templateResource, TEMPLATE_ACTIVE_IMAGE_NAME);
BufferedImage maskTemplate = fixedTemplate;
// 随机生成滑块位置
int randomX = randomInt(fixedTemplate.getWidth() + 5, background.getWidth() - fixedTemplate.getWidth() - 10);
int randomY = randomInt(background.getHeight() - fixedTemplate.getHeight());
// 生成凹槽和滑块
BufferedImage cutImage = CaptchaImageUtils.cutImage(background, maskTemplate, randomX, randomY);
CaptchaImageUtils.overlayImage(background, fixedTemplate, randomX, randomY);
CaptchaImageUtils.overlayImage(cutImage, activeTemplate, 0, 0);
// 合并图片
BufferedImage matrixTemplate = CaptchaImageUtils.createTransparentImage(activeTemplate.getWidth(), background.getHeight());
CaptchaImageUtils.overlayImage(matrixTemplate, cutImage, 0, randomY);
captchaExchange.setBackgroundImage(background);
captchaExchange.setTemplateImage(matrixTemplate);
captchaExchange.setTransferData(new Point(randomX, randomY));
}
3. 验证流程
用户拖动滑块后,前端将滑块的位置信息发送到后端进行验证。后端通过比较用户拖动的位置与生成时的位置,判断验证是否通过。
4. 误差计算
为了提升用户体验,滑动还原验证码通常会允许一定的误差范围。例如,SliderCaptchaPercentageValidator 会计算用户拖动位置与生成位置的百分比误差,判断是否在允许范围内。
@Override
public boolean checkPercentage(MatchParam matchParam, ImageCaptchaTrack track, float percentage) {
Point point = track.getPoint();
int x = point.x;
int y = point.y;
int targetX = matchParam.getX();
int targetY = matchParam.getY();
float xPercentage = Math.abs(x - targetX) / (float) matchParam.getWidth();
float yPercentage = Math.abs(y - targetY) / (float) matchParam.getHeight();
return xPercentage <= percentage && yPercentage <= percentage;
}
5. 安全优化
为了防止自动化攻击,滑动还原验证码通常会加入以下安全优化:
- 混淆凹槽:在背景图片中随机生成多个凹槽,增加识别难度。
- 动态模板:每次生成验证码时随机选择不同的滑块和凹槽模板。
- 行为分析:记录用户的拖动行为,分析是否为机器操作。
通过以上步骤,滑动还原验证码能够有效区分人类用户和自动化脚本,保障系统安全。
文字点选验证码实现原理
文字点选验证码是一种常见的验证码类型,用户需要按照提示点击图片中的特定文字或字符,以证明其非机器操作。本节将深入探讨 tianai-captcha 中文字点选验证码的实现原理,包括生成逻辑、校验机制以及核心代码解析。
1. 验证码生成流程
文字点选验证码的生成流程可以分为以下几个步骤:
- 随机生成文字提示:从预设的字符库中随机选取若干字符作为验证码的提示文字。
- 生成点击图片:为每个提示文字生成一个独立的图片,图片中包含随机颜色、字体和旋转角度。
- 生成提示图片:将所有提示文字拼接成一张提示图片,用于展示给用户。
- 组合背景与提示:将背景图片和提示图片组合,生成最终的验证码图片。
以下是一个流程图展示生成流程:
2. 核心代码解析
StandardWordClickImageCaptchaGenerator 是文字点选验证码的核心实现类,继承自 AbstractClickImageCaptchaGenerator。以下是其关键方法:
2.1 随机生成文字提示
@Override
protected List<Resource> 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<Resource> tipList = new ArrayList<>(tipSize);
for (int i = 0; i < tipSize; i++) {
String randomWord = FontUtils.getRandomChar(random);
tipList.add(new Resource(null, randomWord));
}
return tipList;
}
2.2 生成点击图片
@Override
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 = randomFont();
Font font = fontWrapper.getFont();
float currentFontTopCoef = fontWrapper.getCurrentFontTopCoef();
BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor,
tip.getData(),
font,
currentFontTopCoef,
clickImgWidth,
clickImgHeight,
randomDeg);
return new ImgWrapper(fontImage, tip, randomColor);
}
2.3 生成提示图片
public ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions) {
FontWrapper fontWrapper = randomFont();
Font font = fontWrapper.getFont();
float currentFontTopCoef = fontWrapper.getCurrentFontTopCoef();
String tips = imageCheckDefinitions.stream().map(c -> c.getTip().getData()).collect(Collectors.joining());
int fontWidth = tips.length() * font.getSize();
int width = fontWidth + 6;
int height = font.getSize() + 6;
float left = (width - fontWidth) / 2f;
float top = 6 / 2f + font.getSize() - currentFontTopCoef;
BufferedImage bufferedImage = CaptchaImageUtils.genSimpleImgCaptcha(tips,
font, width, height, left, top, tipImageInterferenceLineNum, tipImageInterferencePointNum);
return new ImgWrapper(bufferedImage, new Resource(null, tips), null);
}
3. 验证码校验机制
校验机制由 SimpleImageCaptchaValidator 实现,核心逻辑如下:
- 提取用户点击数据:从用户提交的数据中提取点击坐标和顺序。
- 匹配点击位置:将用户点击位置与生成的验证码数据中的正确位置进行比对。
- 计算容错范围:允许一定的点击误差,提高用户体验。
以下是校验逻辑的伪代码:
public boolean validate(ImageCaptchaTrack track, List<ClickImageCheckDefinition> checkDefinitions) {
for (ClickImageCheckDefinition definition : checkDefinitions) {
if (!isClickInRange(track.getClickX(), track.getClickY(), definition.getX(), definition.getY())) {
return false;
}
}
return true;
}
4. 总结
文字点选验证码通过随机生成提示文字、动态生成点击图片以及严格的校验机制,有效防止了机器自动化操作。其核心实现类 StandardWordClickImageCaptchaGenerator 和 SimpleImageCaptchaValidator 提供了高度可配置的选项,适应不同场景的需求。
总结
本文系统介绍了dromara/tianai-captcha的四种验证码实现方案,涵盖图像处理、随机化生成、行为验证等核心技术。通过详细的流程图、类图和代码示例,展示了如何构建高安全性、用户体验良好的验证码系统。这些方案能有效防御自动化攻击,适用于各类需要人机验证的场景。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



