图形验证码从设计到实现

在这里插入图片描述

验证码的使用场景

图形验证码在我们的日常使用中是非常常见的,比如一些App、小程序、PC网站等。涉及到的业务也比较广泛、例如用户登录流程、注册流程、找回密码。下面我们来大致梳理下上述流程:

  1. 登录流程
  • 用户首先在登录界面输入手机号
  • 然后通过图形验证码验证,只有成功通过验证码后才能继续下一步
  • 成功通过图形验证码后,系统向用户手机发送一条包含数字验证码的短信
  • 用户收入收到的验证码,系统验证无误后允许登录
  1. 注册流程
  • 用户填写基本信息,包括手机号
  • 提交信息前需要通过图形验证码验证
  • 通过图形验证码后,系统发送短信验证码到用户手机
  • 用户输入短信验证码完成注册过程
  1. 找回密码
  • 用户输入与账号关联的手机号
  • 进行图形验证码验证
  • 通过验证后,系统发送密码重置链接或重置密码所需的验证码至用户的手机
  • 用户按照指引重置密码

验证码的生成步骤

知道了验证码的使用区域,下面来简单说下验证码的生成

  1. 背景生成
    • 选择一个随机颜色作为背景色。
    • 可以添加一些随机的干扰线条或点来增加破解难度。
  2. 字符生成
    • 从预设的字符集中随机选取几个字符组成验证码字符串。这些字符可以是数字、小写字母或大写字母
    • 对于每个字符,可以随机选择不同的字体、大小以及倾斜度。
  3. 字符渲染
    • 将生成的字符绘制在背景上。为了进一步提高安全性,可以对字符应用扭曲效果或者随机旋转一定角度
    • 字符之间的间距也应该是随机的,以便于增加识别难度
  4. 噪声添加
    • 在背景中随机位置添加噪声点或线,这有助于迷惑OCR(光学字符识别)工具。
    • 可以使用不同的颜色和形状,使得噪声更加自然。
  5. 图形变形
    • 整个图像可以应用轻微的扭曲或变形,以使得验证码更难以被自动化工具识别。
  6. 输出图像
    • 最后将处理好的图像输出为JPEG或PNG格式,并且可能还需要设置适当的分辨率和压缩级别以保证质量
  7. 存储验证码值及过期机制
    • 验证码的实际文本需要存储在服务器端,并且通常会关联一个会话ID或者令牌,这样当用户提交表单时,可以验证输入是否正确
    • 设置验证码的有效时间,超出这个时间则认为验证码无效。

验证码的代码实现

创建springBoot项目,导入kaptcha相关依赖

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>kaptcha-spring-boot-starter</artifactId><version>1.1.0</version></dependency>

配置验证码的生成方法

/*** @Author: LiFly* @Date: 2024/8/27 17:05* @Description:*/
@Configuration
public class CaptchaConfig {private static final String CHAR_LENGTH = "4";private static final String CHAR_SPACE = "8";private static final String CAPTCHA_NOISE_IMPL = "com.google.code.kaptcha.impl.NoNoise";private static final String CAPTCHA_SCARIFICATION_IMPL = "com.google.code.kaptcha.impl.WaterRipple";private static final String KAPTCHA_TEXTPRODUCER_CHAR_STRING = "0123456789";/*** 验证码配置* @return 获取默认验证码配置*/@Bean@Qualifier("captchaProducer")public DefaultKaptcha kaptcha(){DefaultKaptcha kaptcha = new DefaultKaptcha();Properties properties = new Properties();//验证码个数properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH,CHAR_LENGTH);//字体间隔properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE,CHAR_SPACE);//干扰实现类properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, CAPTCHA_NOISE_IMPL);//图片样式properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, CAPTCHA_SCARIFICATION_IMPL);//文字来源properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING,KAPTCHA_TEXTPRODUCER_CHAR_STRING);Config config = new Config(properties);kaptcha.setConfig(config);return kaptcha;}
}

配置redis的序列化方式

/*** @Author: LiFly* @Date: 2024/8/27 16:39* @Description:*/
@Configuration
public class RedisTemplateConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);//使用Jackson2JsonRedisSerialize替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);//设置key和value的序列化规则redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);//设置hashKey和hashValue的序列化规则redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);//设置支持事务redisTemplate.setEnableTransactionSupport(true);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

redis相关链接配置也加上

spring.redis.host=127.0.0.1
spring.redis.port=6379
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active = 10
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle = 10
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle = 0
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait= -1ms
#指定客户端
spring.redis.client-type = lettuce
#配置文件指定缓存类型
spring.cache.type=redis

下面我们来开发获取验证码的接口

 @ApiOperation("获取验证码")@GetMapping("/getCaptcha")public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {//创建验证码String captchaText = captchaProducer.createText();//缓存验证码redisTemplate.opsForValue().set(getCaptchaKey(request), captchaText,CAPTCHA_EXPIRE_TIME, TimeUnit.MILLISECONDS);//创建图形验证码BufferedImage bufferedImage = captchaProducer.createImage(captchaText);//返回图形验证码ServletOutputStream out = null;try {out = response.getOutputStream();ImageIO.write(bufferedImage,"jpg",out);out.flush();out.close();}catch (Exception e){log.error("获取图形验证码失败!e={}",e.getMessage());}}/*** 获取缓存key* @param request 请求参数* @return 组装key*/private String getCaptchaKey(HttpServletRequest request){String ip = CommonUtil.getIpAddr(request);String userAgent = request.getHeader("User-Agent");return "user-service:captcha:" + CommonUtil.MD5(ip+userAgent);}

获取验证码的接口非常简单,调用验证码配置类获取验证码,将获取到的验证码缓存到redis中并设置过期时间,然后调用配置类传入验证码获取到图形验证码,通过IO流返回。下面校验验证码

   @ApiOperation("校验验证码")@PostMapping("/sendCode")public JsonData sendCode(@RequestParam(value = "to",required = true)String to,@RequestParam(value = "captcha",required = true) String captcha,HttpServletRequest request) {String key = getCaptchaKey(request);String cacheCaptcha = redisTemplate.opsForValue().get(key);if (cacheCaptcha != null && captcha != null && cacheCaptcha.equals(captcha)) {redisTemplate.delete(key);//发送验证码return JsonData.buildSuccess();}else {return JsonData.buildResult("图形验证码错误");}}

获取前端传过来的手机号以及图形验证码,根据ip以及网络地址相关西信息获取缓存key,根据key获取验证码,然后比较验证码是否一致,如果一致验证通过,删除缓存,执行发送短信相关业务。如果不一致直接返回给前端错误信息。

接口测试

下面我们通过postman来测试下开发的接口,首先获取验证码:
在这里插入图片描述
查看到获取的验证码为5437,再去查看下redis是否存在:
在这里插入图片描述
redis也存在刚才获取的验证码,说明我们获取验证码的接口是没问题的。
再去看下校验验证码的这个接口,
在这里插入图片描述
可以看到,校验验证码的接口也是没问题的,校验验证码后,里面会删除缓存,这时候再来看下缓存中是否还存在:
在这里插入图片描述
刷新缓存为空了,说明检验验证码的接口逻辑是没问题的。后续就可以执行发送短信验证码了。
上述我们主要讲述了用户登录获取验证码的逻辑,用户注册,找回密码逻辑都是差不多一样的,只是后续的处理不太一样,在这里就不再过多讲述了。
总之,图形验证码与手机号验证码的结合使用,不仅增强了系统的安全性,也为用户提供了便捷的操作体验。未来,随着更多创新技术的应用,验证码系统将会变得更加智能和人性化,更好地服务于广大用户。希望本文能为开发者们提供一些有价值的参考,帮助大家在实际工作中构建更加稳固的安全防线。
更多精彩内容请关注以下公众号
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/418670.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VMware时提示系统尚未修改安装失败

安装VMware安装失败&#xff0c;提示系统尚未修改 有以下解决方案&#xff1a; 1.操作系统不兼容 2.安装文件损坏 3.安装程序错误 4.硬件问题 解决&#xff1a;由于重装系统前&#xff0c;安装过VAware&#xff0c;所以应该操作系统&#xff0c;硬件没有问题。下载一个软件v…

关于Redis集群同步/持久化/淘汰机制的详解

Redis是非常常用的KV数据库, 使用内存以及HashMap进行存储的特点带来了高效的查询. 本文将围绕Redis的常见开发使用场景, 阐述在Redis集群中各个节点是如何进行数据同步, 每个节点如何进行持久化以及在长期使用中如何对数据进行更新和淘汰. 如果对Redis有更多的兴趣, 可以查看我…

Java中方法的使用详解

1.引言 假设有一个美女博主&#xff0c;每次发的照片都特别漂亮 然后该博主的评论区每次都会有很多粉丝的评论&#xff1a; 哇&#xff01;宝宝好漂亮&#xff0c;求上衣链接&#xff01;&#xff01;&#xff01; 老婆亲亲&#xff01;这个口红是什么色号呀&#xff1f; 宝…

【go】内存分配模型

内存是怎么分配给对象的&#xff1f; 内存分配优化的地方是&#xff1f; 讲讲golang内存分配模型&#xff1f; ans: 1.按照对象的大小分配&#xff1a;先算出对象的大小如果是tiny对象&#xff0c;就从tiny block中获取地址和偏移量&#xff0c;将对象打包到mcache;如果是16B以…

Python 在Excel中应用和取消多种不同类型的数据筛选

目录 安装Python Excel处理库 Python 在 Excel 中应用文本筛选 Python 在 Excel 中应用数字筛选 Python 在 Excel 中应用字体颜色、单元格颜色或图标集筛选 Python 在 Excel 中应用日期筛选 Python 在 Excel 中应用动态日期筛选 Python 在 Excel 中筛选空单元格或非空单…

【ArcGIS Pro第一期】界面简介

ArcGIS Pro简介 ArcGIS Pro界面简介1.1 打开工程1.2 使用功能区上的工具 参考 ArcGIS Pro 是一种基于功能区的应用程序。 ArcGIS Pro 窗口顶部的功能区有许多命令可供选择&#xff0c;而根据需要打开的各个窗格&#xff08;可停靠窗口&#xff09;中则提供了更为高级或专用的功…

快速排序(QuickSort)-归并排序(MergeSort)[java编写]

1. 快速排序 1.1 基本概述 快速排序采用分治思想&#xff0c;即在一个无序的序列中选取一个任意的基准元素pivot&#xff0c;利用pivot 将待排序的序列分成两部分&#xff0c;前面部分元素均小于或等于基准元素&#xff0c;后面部分均大于或等于基准元素&#xff0c;然后采用…

参会邀请 | 第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)

第二届机器视觉、图像处理与影像技术国际会议&#xff08;MVIPIT 2024&#xff09;将于2024年9月13日-15日在中国张家口召开。 MVIPIT 2024聚焦机器视觉、图像处理与影像技术&#xff0c;旨在为专家、学者和研究人员提供一个国际平台&#xff0c;分享研究成果&#xff0c;讨论…

算法训练营——day3长度最小子数组

1 长度最小子数组-力扣209&#xff08;中等&#xff09; 1.1 题目&#xff1a; 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返…

基于orangePi的智能家居系统

目录 一.接线图 1.orangePi接线 2.继电器接线 二.语音模块的配置 1.pin脚的配置 2.命令词自定义信息 三.测试 1.通过gpio指令测试烟雾检测器是否正确连接 2.编写脚本测试其他模组接线是否正常 四.人脸识别方案 1.首先开通人脸搜索识别服务 2. 点击产品控制台,向人…

2024年四川省安全员B证证考试题库及四川省安全员B证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年四川省安全员B证证考试题库及四川省安全员B证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大…

ARM----时钟

时钟频率可以是由晶振提供的&#xff0c;我们需要高频率&#xff0c;但是外部接高的晶振会不稳定&#xff0c;所有使用PLL&#xff08;锁相环&#xff09;来放大频率。接下来就让我们学习用外部晶振提供的频率来配置时钟频率。 一.时钟源的选择 在这里我们选择外部晶振作为时钟…

数据库面试题学习

B树和B树 B树 排好序的 节点内部有多个元素 B树 排好序的 节点内多个元素 叶子节点有指针&#xff08;双向指针&#xff09; 非叶子节点冗余了一份在叶子节点 mysql定义B树 InnoDB B树是B树的升级版~ InnoDB b树是怎么产生的 mysql 页 目录 16KB 自增id uuid 一页最多可以存储…

【精选】文件摆渡系统:跨网文件传输的安全与效率之选

文件摆渡系统可以解决哪些问题&#xff1f; 文件摆渡系统&#xff08;File Shuttle System&#xff09;主要是应用于不同网络、网段、区域之间的文件数据传输流转场景&#xff0c; 用于解决以下几类问题&#xff1a; 文件传输问题&#xff1a; 大文件传输&#xff1a;系统可…

Windows bat脚本学习九(srec_cat)

一、简介 srec_cat是一个在嵌入式开发中&#xff0c;使用非常频繁的软件&#xff0c;这里做个常用功能的介绍。 二、常用参数 文件类型 在使用srec_cat指令时&#xff0c;在输入文件和输出文件时&#xff0c;要指明文件的类型&#xff0c;如&#xff1a; input.hex -intel …

2024国赛数学建模C题完整论文:农作物的种植策略

农作物种植策略优化的数学建模研究&#xff08;完整论文&#xff0c;持续更新&#xff0c;大家持续关注&#xff0c;更新见文末名片 &#xff09; 摘要 在本文中&#xff0c;建立了基于整数规划、动态规划、马尔科夫决策过程、不确定性建模、多目标优化、相关性分析、蒙特卡洛…

网络层 VII(IP多播、移动IP)【★★★★★★】

一、IP 多播 1. 多播的概念 多播是让源主机一次发送的单个分组可以抵达用一个组地址标识的若干目的主机&#xff0c;即一对多的通信。在互联网上进行的多播&#xff0c;称为 IP 多播&#xff08;multicast , 以前曾译为组播&#xff09;。 与单播相比&#xff0c;在一对多的…

Linux_kernel移植uboot07

一、移植 根据硬件平台的差异&#xff0c;将代码进行少量的修改&#xff0c;修改过后的代码在目标平台上运行起来 移植还需要考虑硬件环境&#xff0c;驱动只需要考虑内核的环境 二、移植内容 1、移植Uboot uboot属于bootloader的一种&#xff0c;还有其他的bootloader&#x…

【超简单】1分钟解决ppt全文字体一键设置

省流 ppt的全部字体需要在“幻灯片母版”里面&#xff0c;“自定义字体”去设置好标题与正文的字体之后才算全部设置完毕 “视图”---“幻灯片母版” 找到“字体”---“自定义字体” 设置好中文和西文的字体&#xff0c;都可以按照自己的选择来&#xff0c;保存即可 吐槽 之…