滑块图形验证生成逻辑梳理
-
图片的选取
图片一般都是根据项目所在的分类来选择,比如做商城项目会要求产品出一些关于商城的图片来作为验证码的图片;汽车相关的项目会选择一些汽车的图片,但事无绝对,看产品如何选择嘛。选品完成之后,考虑到图片不多,一般会将图片存放入项目的classPath下。但也可以存放在其他地方,比如阿里云oss中,MongoDB中都是可以的。如果存在classPath下,可以直拿来用,无须其他开销,如果存在其他地方,可能涉及到网络开销,花费费用,主要还是看公司规模以及项目组如何选择嘛。 -
背景图与缺口图生成
图片选择完成后,接下来就是如何处理图片返回给前端。服务器会随机选择一张图片作为背景,然后在该图片上随机减除一个区域作为“缺口”,同时保存被裁剪出的这部分区域作为滑块图片。这个过程中,缺口的位置、大小以及现状可以使随机的,以增加验证码的复杂性和安全性。 -
前端获取页面加载
当用户访问需要验证的页面时,服务器将生成的背景图、滑块图以及相关的验证码参数(如缺口坐标)返回给前端。 -
前端界面展示
前端页面显示带有缺口的背景图和滑块图。滑块图通常位于背景图的左侧或上方,用户需要拖动到缺口为止以完成验证。 -
后端验证判断
当用户拖动滑块到缺口位置点击提交后发送到服务器。服务器根据之前保存的缺口坐标和滑块图的尺寸,计算滑块是否准确对其缺口位置(会有偏差,缺口位置与用户拖动的位置不可能百分百对其,控制在指定的偏差距离即可)。
当然处理位置判断外,服务器还可以对用的拖动速度、拖动次数等进行判断。
如果滑块位置正确,校验通过则会返回验证成功的结果,否则,返回验证失败并返回具体的错误信息。
代码实现(主要实现后端相关业务)
如图所示,首先准备了10张图片,后面我们随机选取一种图片,作为画图验证码。
验证码生成
下面我们要制作图形验证码,代码如下:
/**
* 获取图片滑动验证码
* @param mobile
* @return
* @throws IOException
*/
@GetMapping("/getCaptcha/{mobile}")
public VerifyImageBO testCaptha(@PathVariable("mobile") String mobile) throws IOException {
Random random = new Random();
ClassPathResource classPathResource = new ClassPathResource("/images/verify_image_" + random.nextInt(10) + ".png");
BufferedImage randomImage = ImageIO.read(classPathResource.getInputStream());
VerifyImage verifyImage = VerifyImageUtils.getVerifyImage(randomImage);//生成滑动验证图片
VerifyImageBO verifyImageBO = new VerifyImageBO();
verifyImageBO.setSrcImage("data:image/png;base64," + verifyImage.getSrcImage());
verifyImageBO.setCutImage("data:image/png;base64," + verifyImage.getCutImage());
verifyImageBO.setXPosition(verifyImage.getXPosition());
verifyImageBO.setYPosition(verifyImage.getYPosition());
logger.info("获取滑动验证图片 xPosition={},yPosition={}", verifyImageBO.getXPosition(),verifyImageBO.getYPosition());
RedisUtil.set("verifyImage_XPosition_" + mobile, verifyImageBO.getXPosition(), verifyImageCacheTime);
verifyImageBO.setXPosition(0);
return verifyImageBO;
}
从代码中不难理解,前端会传入一个手机号,我们需要存储用户的手机号和背景图片以及剪切的滑块图和剪切的位置,以供下面校验滑块验证码使用。大致逻辑:从classPath中随机获取一种图片,调用工具类生成背景图和剪切图以及剪切的位置,然后将用户手机号以及剪切的位置存入redis中,并设置过期时间,然后将横轴位置设置为0就是背景图的左边,最后返回给前端。
验证码校验
当前端移动滑块,点击提交后会发送到后台,
/**
* 验证滑动验证码
* @param verifyImageSpecification
* @return
*/
@PostMapping("/checkVerifyImage")
public String checkVerifyImage(@RequestBody VerifyImageRequest verifyImageSpecification) {
// 必填参数校验
if (StringUtils.isBlank(verifyImageSpecification.getMobile())) {
return "手机号不能为空!";
}
// 手机号格式校验
if ( !Pattern.matches(mobileReg, verifyImageSpecification.getMobile())) {
return "手机号输入错误";
}
if (verifyImageSpecification.getPosition() == null) {
return "图形验证码滑动参数不能为空";
}
Object obj = RedisUtil.get("verifyImage_XPosition_" + verifyImageSpecification.getMobile());
if (obj == null) {
return "图形验证码不存在";
}
Integer realXPosition = (Integer) obj;
//验证滑动位置是否正确,允许20像素以内误差
int errorValue = realXPosition - verifyImageSpecification.getPosition();
if (errorValue < 20 && errorValue > -20) {
return "校验通过,执行后续逻辑";
}else{
return "图形验证码错误!";
}
}
其实从以上代码中不难看出,主要是对一些参数的校验,手机号,图形验证码等,其实最主要的逻辑就是校验剪切块与原背景图剪切位置的偏移量,当校验都通过就可以执行后续逻辑啦。还有一些其他的拓展信息,比如添加时间戳,多长时间图片失效,增加滑动次数,避免一次不通过还要重新滑动,增加安全性校验。
总结
本文详细介绍了滑块图形验证码的生成逻辑及其后端实现细节。首先,根据项目需求选择合适的背景图片,并将其存储于项目的ClassPath或其他如云存储服务中。接着,服务器随机选取一张图片作为背景,并在其上随机裁剪出一个区域作为滑块,即所谓的“缺口”。此过程中的缺口参数(如位置、大小)是随机生成的,以此增加验证码的安全性。
当用户请求需要验证的页面时,服务器将背景图与滑块图及验证所需的相关参数发送至前端。前端展示这些图像,并允许用户通过拖动滑块来填补缺口,以完成验证。一旦用户提交验证,后端将根据预先保存的缺口坐标与用户实际拖动的位置进行比较,允许一定范围内的误差,以此判断用户操作的有效性。此外,系统还可能分析用户拖动的速度与路径,以进一步提高安全性。
代码示例展示了如何在Java环境中实现这一逻辑,包括如何从ClassPath中随机选取图片、生成滑块和背景图,以及如何将关键数据存储在Redis中以备验证时使用。同时,还提供了验证码校验的具体实现,强调了参数校验的重要性,特别是对用户输入的手机号和滑动位置的准确性进行校验。
更多精彩内容请关注以下公众号