滑动拼图验证码作为用户身份验证的一种方式,它的主要作用是进行人机行为区分,防止针对网站或者应用的恶意机器行为。这种验证码尤其适用于防止恶意的批量注册、登录爬虫以及自动化攻击,比如说防止一些验证码识别的机器人。
基本的滑动拼图验证码通常由一个背景图像和一个缺失的图像片段组成,用户需要通过鼠标操作将缺失的片段准确滑动至应在的位置。在这个过程中,用户的行为数据(包括滑动轨迹,滑动速度,滑动时间等)都可以被用来进行用户和机器的区分,因此滑动拼图验证码又有着非常高的安全性。
与传统的文本验证码相比,滑动拼图验证码具有更好的用户体验和更高的安全性:文本验证码往往需要用户仔细观察,输入错误率高,给用户带来不便,而且现在有许多OCR技术可以成功识别文本验证码。滑动拼图验证码则只需要用户执行一个自然的,直觉的动作,用户错误率低,同时机器人模拟出人类完全一致的行为几乎是不可能的。
理解原理:滑动拼图验证码的运行机制
滑动拼图验证码的运行包括了后端服务和前端交互两大部分,我们先来知道整体的流程,再逐一深入。
- 后端生成图像:后端首先生成一张完整的图像和一个带有缺口的复制图像。这个缺口通常是一个特定的形状,如圆形、方形等,或者是一段特定轮廓的形状。这样就形成了一对背景图像和滑块图像,缺口的形状和大小在这两张图像中是完全一致的。
- 前端展示与交互:后端将这两张图像发送给前端,前端将背景图像正常展示,而滑块图像则位于一边,等待用户进行拖动。
- 用户操作滑块:用户通过鼠标或触屏操作,将滑块图像拖动至背景图像中的缺口部分。在这个操作过程中,前端会记录下用户的行为数据,这些数据包括但不限于滑动开始和结束的时间、滑动轨迹、滑动速度等。
- 前端发送验证数据:当用户完成拖动后,或者用户拖动滑块超出一定范围后,前端将滑动的结果以及行为数据发送给后端。这个结果就是滑块在背景图像中的位置,或者说是滑动的距离。
- 后端验证:后端根据发送来的滑动结果,以及用户的行为数据,进行验证。如果滑动结果与后端最初设定的缺口位置一致,或者在一定的误差范围内,同时用户的行为数据也符合正常人类的行为,那么后端判定这次验证码验证成功,返回验证成功的结果。
技术实现:在Springboot3.x中如何生成滑动拼图验证码
下面我们将实现一个简单的 Spring Boot 工程来生成滑动拼图验证码。我们的项目中主要包括四个部分,分别为原始图片的获取,将原始图片转换为带缺口的滑动验证码图片,前端的验证码显示和操作以及后端的数据验证。
后端:生成滑动拼图验证码
我们首先需要一个原始图片,这个图片将会被转换为验证码图片。原始图片可以是任何图片文件,例如originalImage.png,存放在项目的资源文件夹中。
后端用来生成验证码的核心代码如下:
@RestController
public class ImageController {
private final ImageService imageService;
public ImageController(ImageService imageService) {
this.imageService = imageService;
}
@GetMapping("/captcha")
public ResponseEntity<byte[]> getCaptcha(HttpSession session) throws IOException {
BufferedImage captchaImage = imageService.createCaptchaImage();
session.setAttribute("captcha", imageService.getCaptchaPosition());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(captchaImage, "png", baos);
byte[] imageInByte = baos.toByteArray();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE)
.body(imageInByte);
}
@PostMapping("/validate")
public boolean validateCaptcha(@RequestParam int position, HttpSession session) {
Integer captchaPosition = (Integer) session.getAttribute("captcha");
if (captchaPosition != null) {
return Math.abs(captchaPosition - position) <= 5;
}
return false;
}
}
在这段代码中,/captcha路由用来生成验证码图片并返回给前端,生成的验证码图片是一个PNG格式的图片。同时,将验证码图片中缺口的位置保存在session中,用来进行后续的验证。/validate路由用来验证用户的操作是否正确。
ImageService 类
import org.springframework.stereotype.Service;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import javax.imageio.ImageIO;
import java.util.Random;
@Service
public class ImageService {
private int captchaPosition;
public BufferedImage createCaptchaImage() throws IOException {
BufferedImage originalImage = readImageFromResources();
captchaPosition = generateRandomCaptchaPosition(originalImage.getWidth());
BufferedImage captchaImage = new BufferedImage(
originalImage.getWidth(),
originalImage.getHeight(),
originalImage.getType());
int pieceWidth = originalImage.getWidth() / 8;
// 绘制原始图像
Graphics2D graphics2D = captchaImage.createGraphics();
graphics2D.drawImage(originalImage, 0, 0, null);
// 在原始位置绘制一个带形状的片段
graphics2D.setComposite(AlphaComposite.Clear);
graphics2D.fillRoundRect(captchaPosition, captchaImage.getHeight() / 2, pieceWidth, pieceWidth, 10, 10);
graphics2D.dispose();
return captchaImage;
}
private BufferedImage readImageFromResources() throws IOException {
InputStream inputStream = getClass().getResourceAsStream(Paths.get("path_to_resources", "originalImage.png").toString());
return ImageIO.read(inputStream);
}
private static int generateRandomCaptchaPosition(int width) {
Random random = new Random();
return random.nextInt(width / 2) + width / 4; // 将片段定位到图像的中央位置
}
public int getCaptchaPosition() {
return captchaPosition;
}
}
这个 ImageService 类实现了 createCaptchaImage 方法,这个方法可以生成一个滑动拼图验证码。首先,它读取了一个原始的图像文件,然后随机生成了一个验证码的位置。接着,它创建了一个新的 BufferedImage 对象,将原始图像绘制到了这个新的对象上,然后在验证码位置上绘制了一个透明的缺口。
前端:验证码的显示和操作
前端使用HTML和JavaScript来显示验证码图片和处理用户的操作。核心代码如下:
<img id="captcha" src="api/captcha" />
<div id="slider"><div id="knob"></div></div>
<script>
const slider = document.getElementById('slider');
const knob = document.getElementById('knob');
knob.onmousedown = function(event) {
event.preventDefault();
let shiftX = event.clientX - knob.getBoundingClientRect().left;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
function onMouseMove(event) {
let newLeft = event.clientX - shiftX - slider.getBoundingClientRect().left;
if (newLeft < 0) newLeft = 0;
let rightEdge = slider.offsetWidth - knob.offsetWidth;
if (newLeft > rightEdge) newLeft = rightEdge;
knob.style.left = newLeft + 'px';
}
function onMouseUp() {
document.removeEventListener('mouseup', onMouseUp);
document.removeEventListener('mousemove', onMouseMove);
validateCaptcha(parseInt(knob.style.left));
}
};
knob.ondragstart = function() { return false; }
function validateCaptcha(position) {
fetch('api/validate?position=' + position, {method: 'POST'})
.then(response => response.json())
.then(data => { /* process the validation result */ });
}
</script>
在这段代码中,显示验证码的元素从后端请求验证码图片。滑动条(<div id="slider">)和滑块(<div id="knob">)用来让用户进行操作。当用户按下滑块时,开始记录滑块的位置,当用户释放滑块时,将滑块的位置发送给后端进行验证。
实战应用:滑动拼图验证码的应用示例
滑动拼图验证码是一种常见的人机验证工具,主要用于区别用户是人还是机器人。其操作方式通常是,用户通过拖动滑块,将一个图形拼图从初始位置移动到一个预定的位置,如此一来,系统就可以通过这种操作行为来判断用户是否为人类。下面是一个具体的应用示例:
假如你正在构建一个网站,希望在用户注册或登录时,通过滑动拼图验证码来增强系统的安全防护。在用户填写完用户名和密码后,必须要求他们通过滑动拼图验证码的验证,才能进一步操作。
- 用户首先访问你的网站,并点击注册或登录按钮。
- 用户在相应的输入框内填入用户名和密码。
- 此时,网站会显示出一个滑动拼图验证码,同时,网站也会提示用户需要通过拖动滑块,将拼图移动到正确的位置。
- 用户根据提示操作,移动滑块,将拼图还原到指定位置。
- 用户成功完成滑动拼图验证码后,就可以继续注册或登录操作。
引入滑动拼图验证码,可以有效增强你的网站对恶意机器人的防护能力,从而提高用户数据的安全性。同时,这种方式也很友好,用户体验良好,是一种十分实用的人机交互方式。
本文详细而深入地介绍了滑动拼图验证码的工作原理及其在实战中的应用。文章首先解释了什么是滑动拼图验证码,它如何帮助识别用户是否为人类,提高系统的安全性。然后,文章通过一个具体的实例,详细地描述了如何在用户注册和登录的过程中,使用滑动拼图验证码增强网站的安全防护能力。总结而言,滑动拼图验证码是一种有效且用户体验良好的防护机制,能够针对恶意机器人采取防护措施,提高用户数据的安全性。