若依源码解析:图片验证码生成

news/2024/10/29 2:31:12/

文章目录

  • 摘要
  • 生成图片验证码的过程
  • 若依中的验证码生成控制器:CaptchaController
  • 验证码文本生成器:KaptchaTextCreator

摘要

若依通过合理的验证码生成流程和相应的代码实现,为应用程序提供了生成图片验证码和基于数学运算的验证码文本的功能,以增加系统的安全性和防护能力。
本文讨论了若依(Ruoyi)生成图片验证码的过程以及相关代码。首先,我们了解了生成图片验证码的基本步骤,包括生成随机字符串、创建图片对象、绘制背景和文本、添加干扰线等。
接下来,我们分析了若依中的验证码生成控制器,它根据配置的验证码类型,在后台生成对应类型的验证码,并将验证码图片以Base64编码的形式返回给前端页面。
最后,我们解释了一个自定义的验证码文本生成器,它生成基于数学运算的验证码文本,要求用户进行计算并输入结果进行验证。这种验证码形式提高了安全性和防止自动化攻击的能力。

生成图片验证码的过程

生成图片验证码的过程包括生成随机字符串、创建图片对象、绘制背景和文本、添加干扰线、图像处理和输出验证码。这样生成的验证码图片可以用于用户身份验证、防止机器人攻击等安全性相关的场景。具体步骤如下:

  1. 生成随机字符串:首先,使用随机算法生成一串指定长度的随机字符串,通常是包含数字和字母的组合。该字符串将成为验证码的文本内容。

  2. 创建验证码图片:使用Java的图形处理库,如Java 2D或JavaFX,创建一个空白图片。一般情况下,图片的尺寸是固定的,如宽度为100像素,高度为40像素。

  3. 绘制背景:可以选择在验证码图片上绘制一些干扰背景,以增加验证码的安全性。例如,可以绘制一些随机的干扰线、噪点或颜色块。

  4. 绘制文本:使用字体库从系统中选择一个字体,将生成的随机字符串绘制到验证码图片上。为了增加验证码的可读性,通常会随机选择一种字体、字号和颜色,并将每个字符绘制在图片上不同的位置。

  5. 添加干扰线:为了增加验证码的复杂度和防止自动识别,可以在图片上绘制一些干扰线。这些干扰线可以是随机位置、随机颜色和随机形状的线条。

  6. 图片处理:对生成的验证码图片进行一些图像处理操作,例如模糊、扭曲或旋转等,以增加验证码的复杂度和安全性。

  7. 输出验证码:最后,将生成的验证码图片以某种方式输出给用户,通常是通过HTTP响应返回给前端页面。前端页面可以将该图片显示给用户,并且用户需要输入验证码的文本内容进行验证。

若依中的验证码生成控制器:CaptchaController

若依(Ruoyi)通过CaptchaController来生成验证码并返回给前端页面。根据配置的验证码类型,在后台生成对应类型的验证码,并将验证码的实际值存入缓存中,然后将验证码图片以Base64编码的形式返回给前端页面。

@RestController
public class CaptchaController
{@Resource(name = "captchaProducer")private Producer captchaProducer;@Resource(name = "captchaProducerMath")private Producer captchaProducerMath;@Autowiredprivate RedisCache redisCache;// 验证码类型@Value("${ruoyi.captchaType}")private String captchaType;@Autowiredprivate ISysConfigService configService;/*** 生成验证码*/@GetMapping("/captchaImage")public AjaxResult getCode(HttpServletResponse response) throws IOException{AjaxResult ajax = AjaxResult.success();boolean captchaOnOff = configService.selectCaptchaOnOff();ajax.put("captchaOnOff", captchaOnOff);if (!captchaOnOff){return ajax;}// 保存验证码信息String uuid = IdUtils.simpleUUID();String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;String capStr = null, code = null;BufferedImage image = null;// 生成验证码if ("math".equals(captchaType)){String capText = captchaProducerMath.createText();capStr = capText.substring(0, capText.lastIndexOf("@"));code = capText.substring(capText.lastIndexOf("@") + 1);image = captchaProducerMath.createImage(capStr);}else if ("char".equals(captchaType)){capStr = code = captchaProducer.createText();image = captchaProducer.createImage(capStr);}redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);// 转换流信息写出FastByteArrayOutputStream os = new FastByteArrayOutputStream();try{ImageIO.write(image, "jpg", os);}catch (IOException e){return AjaxResult.error(e.getMessage());}ajax.put("uuid", uuid);ajax.put("img", Base64.encode(os.toByteArray()));return ajax;}
}

逐步解释这段代码的主要部分:

  1. 控制器注解:@RestController 注解表示这是一个RESTful风格的控制器,用于处理HTTP请求并返回JSON格式的响应。

  2. 注入依赖:@Resource@Autowired 注解用于依赖注入。captchaProducercaptchaProducerMath 是生成验证码的 Producer 对象,redisCache 是 Redis 缓存对象,configService 是系统配置服务。

  3. 属性注入:@Value 注解用于从配置文件中读取属性值。captchaType 是验证码的类型,该值通过 ruoyi.captchaType 属性指定。

  4. getCode 方法:@GetMapping("/captchaImage") 注解表示处理GET请求的 /captchaImage 路径。该方法用于生成验证码并返回给前端页面。

  5. 验证码开关判断:首先,通过 configService.selectCaptchaOnOff() 方法判断验证码的开关状态,将结果存入 captchaOnOff 变量,并将其放入 AjaxResult 对象中返回给前端。

  6. 生成验证码:根据 captchaType 的值选择不同类型的验证码生成方式。如果 captchaType 是 “math”,则使用 captchaProducerMath 生成基于数学运算的验证码;如果 captchaType 是 “char”,则使用 captchaProducer 生成基于字符的验证码。同时,记录生成的验证码字符串 capStr 和验证码的实际值 code,并生成验证码图片 image

  7. 保存验证码信息:生成一个唯一的 uuid 作为验证码的标识符,将 code 存入 Redis 缓存中,并设置过期时间为 Constants.CAPTCHA_EXPIRATION 分钟。

  8. 图片转换和返回:将生成的验证码图片转换为字节数组,使用 Base64.encode 方法将字节数组转换为字符串,并将 uuid 和图片字符串放入 AjaxResult 对象中返回给前端。

验证码文本生成器:KaptchaTextCreator

这段代码是一个验证码文本生成器,用于生成基于数学运算的验证码文本。该验证码文本生成器在生成验证码时,采用基于数学运算的方式,使得用户需要计算验证码的结果,并输入到验证码输入框中进行验证。这种验证码形式增加了安全性和防止自动化攻击的能力。

/*** 验证码文本生成器* * @author ruoyi*/
public class KaptchaTextCreator extends DefaultTextCreator
{private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");@Overridepublic String getText(){Integer result = 0;Random random = new Random();int x = random.nextInt(10);int y = random.nextInt(10);StringBuilder suChinese = new StringBuilder();int randomoperands = (int) Math.round(Math.random() * 2);if (randomoperands == 0){result = x * y;suChinese.append(CNUMBERS[x]);suChinese.append("*");suChinese.append(CNUMBERS[y]);}else if (randomoperands == 1){if (!(x == 0) && y % x == 0){result = y / x;suChinese.append(CNUMBERS[y]);suChinese.append("/");suChinese.append(CNUMBERS[x]);}else{result = x + y;suChinese.append(CNUMBERS[x]);suChinese.append("+");suChinese.append(CNUMBERS[y]);}}else if (randomoperands == 2){if (x >= y){result = x - y;suChinese.append(CNUMBERS[x]);suChinese.append("-");suChinese.append(CNUMBERS[y]);}else{result = y - x;suChinese.append(CNUMBERS[y]);suChinese.append("-");suChinese.append(CNUMBERS[x]);}}else{result = x + y;suChinese.append(CNUMBERS[x]);suChinese.append("+");suChinese.append(CNUMBERS[y]);}suChinese.append("=?@" + result);return suChinese.toString();}
}

让我逐步解释这段代码的主要部分:

  1. 类定义和继承:KaptchaTextCreator 类继承自 DefaultTextCreator,后者是 kaptcha 库中提供的默认文本生成器。

  2. 静态常量定义:CNUMBERS 是一个包含数字0到10的字符串数组。

  3. getText 方法重写:重写了父类的 getText 方法,用于生成验证码的文本内容。

  4. 生成验证码文本:首先,通过 Random 类生成两个随机数 xy,范围为0到9。然后,根据随机操作数的值 randomoperands,进行不同的数学运算。

    • 如果 randomoperands 是0,表示进行乘法运算。将 xy 相乘,将运算表达式和结果添加到 suChinese 字符串中。
    • 如果 randomoperands 是1,表示进行除法或加法运算。如果 x 不为0,并且 y 能整除 x,则进行除法运算,将结果添加到 suChinese 中;否则进行加法运算,将结果添加到 suChinese 中。
    • 如果 randomoperands 是2,表示进行减法运算。如果 x 大于等于 y,进行 x - y 运算,否则进行 y - x 运算,将结果添加到 suChinese 中。
    • 如果 randomoperands 不是上述情况,表示进行加法运算,将 xy 相加,将运算表达式和结果添加到 suChinese 中。
  5. 返回验证码文本:最后,将运算表达式和结果连接为一个字符串,并添加特殊字符 “=?@”,最终返回生成的验证码文本。


http://www.ppmy.cn/news/97727.html

相关文章

【前端】关于如何将html、js、css等一个html网页打包成单一的exe可执行程序文件

要将 HTML、JS、CSS 等一个 HTML 网页打包成单一的可执行程序文件(exe),通常需要使用一些工具和框架来实现的。 这里以Electron为例,详细说一下具体的打包过程 1.安装依赖: 确保已经安装了 Node.js。在命令行中进入你…

笔记 | FastAPI创建新项目

当使用FastAPI创建项目时,首先需要安装FastAPI和其依赖项。可以使用pip来安装它们。请确保已经安装了Python和pip。 创建项目文件夹并进入该文件夹: mkdir myproject cd myproject创建并激活一个新的Python虚拟环境(可选,但强烈…

15.Kafka系列之事务原理及实践

我们先来回顾下6.Kafka系列之设计思想(四)-消息传递语义中的一些内容 1. 消息传递保证 At most once:最多一次。消息可能会丢失,但永远不会重新传递At least once:至少一次。消息永远不会丢失,但可能会重新传递Exactly once&…

微服务设计原则--笔记

微服务设计原则–笔记 单一职责原则 单一职责原则指的是一个单元(类、方法或者服务等)只应关注系统功能中单独、有界限的一部分。单一职责原则可以帮助我们优雅的开发、敏捷的交付。单一职责也是SOLID原则之一。 接口隔离原则 服务之间的交互应该基于…

定积分的计算(换元法)

前置知识: 第一类换元法(凑微分法)第二类换元法牛顿-莱布尼茨公式 定积分换元法 设 f f f在 [ a , b ] [a,b] [a,b]上连续, φ \varphi φ在 [ α , β ] [\alpha,\beta] [α,β]上可导且导数连续, x φ ( t ) x\v…

基于html+css的图展示96

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

3ds MAX 基本体建模,长方体、圆柱体和球体

3ds MAX基本页面如下: 生成新的几何体在右侧: 选择生成的对象类型即可,以下为例子: 1、长方体建模 选择建立的对象类型为长方形 在 任意一个窗口绘制,鼠标滑动 这里选择左上角的俯视图 松开鼠标后,可以…

【Docker】什么是Dockerfile

🌳🌳【Docer篇整理】🌳🌳 篇一:docker核心概念与常用指令 篇二:镜像与docker数据卷 篇三:dockerfile 篇四:docker网络 文章目录 1、认识DockerFile2、DockerFile的构建过程3、Docke…