基于springboot Vue3的两种图形验证码工具——vue3-puzzle-vcode纯前端防人 ...

打印 上一主题 下一主题

主题 981|帖子 981|积分 2943

一.vue3-puzzle-vcode

        Vue 纯前端的拼图人机验证、右滑拼图验证
官网:
vue3-puzzle-vcode - npm (npmjs.com)
https://www.npmjs.com/package/vue3-puzzle-vcode


1.1基本使用步骤

安装

   npm install vue-puzzle-vcode --save
  简朴例子

点击开始验证按钮弹出验证弹窗
  1. <template>
  2.     <Vcode :show="isShow" @success="onSuccess" @close="onClose"/>
  3.     <button @click="onShow">开始验证</button>
  4. </template>
  5. <script setup>
  6.   import { ref } from "vue";
  7.   import Vcode from "vue3-puzzle-vcode";
  8.   const isShow = ref(false);
  9.   const onShow = () => {
  10.     isShow.value = true;
  11.   };
  12.   const onClose = () => {
  13.     isShow.value = false;
  14.   };
  15.   const onSuccess = () => {
  16.     onClose(); // 验证成功,手动关闭模态框
  17.   };
  18. </script>
复制代码
注:更多参数信息设置请参考官网文档
二.kaptcha


        kaptcha 是谷歌开源的非常实用的验证码生成工具,基于SimpleCaptcha的开源项目。使用Kaptcha 生成验证码非常简朴并且参数可以举行自界说。只需添加jar包设置下就可以使用,通过设置,可以自己界说验证码巨细、颜色、显示的字符等等。
官网:code.google.com
https://code.google.com/p/kaptcha/
验证码的一般流程
后端:


  • 随机生成图片验证码
  • 结合随机生成的UUID作为Key,验证码值作为Value生存验证码到Redis中
  • 将UUID和验证码图片响应给用户,等用户提交后验证校验码是否有效
前端:


  • 进入登录/注册页面时,获取验证码图片
  • 提供革新验证码的动作,防止出现用户难以辨识的辨认码
2.1基本的使用步骤

导入POM依靠

  1. <!-- Kaptcha 依赖(验证码) -->
  2.         <dependency>
  3.             <groupId>com.github.penggle</groupId>
  4.             <artifactId>kaptcha</artifactId>
  5.             <version>2.3.2</version>
  6.         </dependency>
复制代码
KaptchaConfig设置类

该设置类用于给验证码的设置提供设置,如宽高,颜色等等
  1. import com.google.code.kaptcha.impl.DefaultKaptcha;
  2. import com.google.code.kaptcha.util.Config;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import java.util.Properties;
  6. import static com.google.code.kaptcha.Constants.*;
  7. /**
  8. * 验证码配置
  9. */
  10. @Configuration
  11. public class KaptchaConfig {
  12.     @Bean(name = "captchaProducer")
  13.     public DefaultKaptcha getKaptchaBean() {
  14.         DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
  15.         Properties properties = new Properties();
  16.         // 是否有边框 默认为true 我们可以自己设置yes,no
  17.         properties.setProperty(KAPTCHA_BORDER, "no");
  18.         // 验证码文本字符颜色 默认为Color.BLACK
  19.         properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
  20.         // 验证码图片宽度 默认为200
  21.         properties.setProperty(KAPTCHA_IMAGE_WIDTH, "200");
  22.         // 验证码图片高度 默认为50
  23.         properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
  24.         // 验证码文本字符大小 默认为40
  25.         properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
  26.         // KAPTCHA_SESSION_KEY
  27.         properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
  28.         // 验证码文本字符长度 默认为5
  29.         properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
  30.         // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
  31.         properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
  32.         // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
  33.         properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
  34.         Config config = new Config(properties);
  35.         defaultKaptcha.setConfig(config);
  36.         return defaultKaptcha;
  37.     }
  38. }
复制代码
整合Redis

   Redis是一个开源的内存数据库,属于NoSQL数据库的一种。它以高性能、支持丰富的数据结构、持久化特性、复制、集群以及发布/订阅等特性而闻名。
  使用Redis给验证码设置有效期
引入依靠
  1. <!-- redis 缓存操作 -->
  2.         <dependency>
  3.             <groupId>org.springframework.boot</groupId>
  4.             <artifactId>spring-boot-starter-data-redis</artifactId>
  5.         </dependency>
复制代码
设置yml文件
  1. server:
  2.   port: 8080
  3.   address: 127.0.0.1
  4. spring:
  5.   #  redis配置
  6.   redis:
  7.     host: localhost
  8.     port: 6379
  9. #spring事务管理日志
  10. logging:
  11.   level:
  12.     org.springframework.jdbc.support.JdbcTransactionManager: debug
复制代码
Redis设置类
  1. package com.hl;
  2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  3. import com.fasterxml.jackson.annotation.JsonTypeInfo;
  4. import com.fasterxml.jackson.annotation.PropertyAccessor;
  5. import com.fasterxml.jackson.databind.ObjectMapper;
  6. import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10. import org.springframework.data.redis.connection.RedisConnectionFactory;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.data.redis.core.ValueOperations;
  13. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  14. import org.springframework.data.redis.serializer.StringRedisSerializer;
  15. @Configuration
  16. public class RedisConfig {
  17.     @Autowired
  18.     private RedisConnectionFactory factory;
  19.     @Bean
  20.     public RedisTemplate<String, Object> redisTemplate() {
  21.         //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
  22.         Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
  23.         ObjectMapper om = new ObjectMapper();
  24.         // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
  25.         om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  26.         // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
  27.         //om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  28.         om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
  29.         jackson2JsonRedisSerializer.setObjectMapper(om);
  30.         RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
  31.         template.setConnectionFactory(factory);
  32.         template.setKeySerializer(new StringRedisSerializer()); //指定Redis的Key序列化方式
  33.         template.setValueSerializer(jackson2JsonRedisSerializer); //指定Value的序列化方式
  34.         template.setHashKeySerializer(jackson2JsonRedisSerializer); //执行Hash的Key的序列化方式
  35.         template.setHashValueSerializer(jackson2JsonRedisSerializer); //指定Hash的Value的序列化方式
  36.         template.setDefaultSerializer(new StringRedisSerializer());
  37.         template.afterPropertiesSet();
  38.         return template;
  39.     }
  40.     @Bean
  41.     public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
  42.         return redisTemplate.opsForValue();
  43.     }
  44. }
复制代码
Redis工具类(整合Redis的一些操作)
  1. package com.hl;
  2. import java.util.Collection;
  3. import java.util.Iterator;
  4. import java.util.List;
  5. import java.util.Map;
  6. import java.util.Set;
  7. import java.util.concurrent.TimeUnit;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.data.redis.core.BoundSetOperations;
  10. import org.springframework.data.redis.core.HashOperations;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.data.redis.core.ValueOperations;
  13. import org.springframework.stereotype.Component;
  14. /**
  15. * spring redis 工具类
  16. *
  17. **/
  18. @SuppressWarnings(value = { "unchecked", "rawtypes" })
  19. @Component
  20. public class RedisCache
  21. {
  22.     @Autowired
  23.     public RedisTemplate redisTemplate;
  24.     /**
  25.      * 缓存基本的对象,Integer、String、实体类等
  26.      *
  27.      * @param key 缓存的键值
  28.      * @param value 缓存的值
  29.      */
  30.     public <T> void setCacheObject(final String key, final T value)
  31.     {
  32.         redisTemplate.opsForValue().set(key, value);
  33.     }
  34.     /**
  35.      * 缓存基本的对象,Integer、String、实体类等
  36.      *
  37.      * @param key 缓存的键值
  38.      * @param value 缓存的值
  39.      * @param timeout 时间
  40.      * @param timeUnit 时间颗粒度
  41.      */
  42.     public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
  43.     {
  44.         redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
  45.     }
  46.     /**
  47.      * 设置有效时间
  48.      *
  49.      * @param key Redis键
  50.      * @param timeout 超时时间
  51.      * @return true=设置成功;false=设置失败
  52.      */
  53.     public boolean expire(final String key, final long timeout)
  54.     {
  55.         return expire(key, timeout, TimeUnit.SECONDS);
  56.     }
  57.     /**
  58.      * 设置有效时间
  59.      *
  60.      * @param key Redis键
  61.      * @param timeout 超时时间
  62.      * @param unit 时间单位
  63.      * @return true=设置成功;false=设置失败
  64.      */
  65.     public boolean expire(final String key, final long timeout, final TimeUnit unit)
  66.     {
  67.         return redisTemplate.expire(key, timeout, unit);
  68.     }
  69.     /**
  70.      * 获取有效时间
  71.      *
  72.      * @param key Redis键
  73.      * @return 有效时间
  74.      */
  75.     public long getExpire(final String key)
  76.     {
  77.         return redisTemplate.getExpire(key);
  78.     }
  79.     /**
  80.      * 判断 key是否存在
  81.      *
  82.      * @param key 键
  83.      * @return true 存在 false不存在
  84.      */
  85.     public Boolean hasKey(String key)
  86.     {
  87.         return redisTemplate.hasKey(key);
  88.     }
  89.     /**
  90.      * 获得缓存的基本对象。
  91.      *
  92.      * @param key 缓存键值
  93.      * @return 缓存键值对应的数据
  94.      */
  95.     public <T> T getCacheObject(final String key)
  96.     {
  97.         ValueOperations<String, T> operation = redisTemplate.opsForValue();
  98.         return operation.get(key);
  99.     }
  100.     /**
  101.      * 删除单个对象
  102.      *
  103.      * @param key
  104.      */
  105.     public boolean deleteObject(final String key)
  106.     {
  107.         return redisTemplate.delete(key);
  108.     }
  109.     /**
  110.      * 删除集合对象
  111.      *
  112.      * @param collection 多个对象
  113.      * @return
  114.      */
  115.     public boolean deleteObject(final Collection collection)
  116.     {
  117.         return redisTemplate.delete(collection) > 0;
  118.     }
  119.     /**
  120.      * 缓存List数据
  121.      *
  122.      * @param key 缓存的键值
  123.      * @param dataList 待缓存的List数据
  124.      * @return 缓存的对象
  125.      */
  126.     public <T> long setCacheList(final String key, final List<T> dataList)
  127.     {
  128.         Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
  129.         return count == null ? 0 : count;
  130.     }
  131.     /**
  132.      * 获得缓存的list对象
  133.      *
  134.      * @param key 缓存的键值
  135.      * @return 缓存键值对应的数据
  136.      */
  137.     public <T> List<T> getCacheList(final String key)
  138.     {
  139.         return redisTemplate.opsForList().range(key, 0, -1);
  140.     }
  141.     /**
  142.      * 缓存Set
  143.      *
  144.      * @param key 缓存键值
  145.      * @param dataSet 缓存的数据
  146.      * @return 缓存数据的对象
  147.      */
  148.     public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
  149.     {
  150.         BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
  151.         Iterator<T> it = dataSet.iterator();
  152.         while (it.hasNext())
  153.         {
  154.             setOperation.add(it.next());
  155.         }
  156.         return setOperation;
  157.     }
  158.     /**
  159.      * 获得缓存的set
  160.      *
  161.      * @param key
  162.      * @return
  163.      */
  164.     public <T> Set<T> getCacheSet(final String key)
  165.     {
  166.         return redisTemplate.opsForSet().members(key);
  167.     }
  168.     /**
  169.      * 缓存Map
  170.      *
  171.      * @param key
  172.      * @param dataMap
  173.      */
  174.     public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
  175.     {
  176.         if (dataMap != null) {
  177.             redisTemplate.opsForHash().putAll(key, dataMap);
  178.         }
  179.     }
  180.     /**
  181.      * 获得缓存的Map
  182.      *
  183.      * @param key
  184.      * @return
  185.      */
  186.     public <T> Map<String, T> getCacheMap(final String key)
  187.     {
  188.         return redisTemplate.opsForHash().entries(key);
  189.     }
  190.     /**
  191.      * 往Hash中存入数据
  192.      *
  193.      * @param key Redis键
  194.      * @param hKey Hash键
  195.      * @param value 值
  196.      */
  197.     public <T> void setCacheMapValue(final String key, final String hKey, final T value)
  198.     {
  199.         redisTemplate.opsForHash().put(key, hKey, value);
  200.     }
  201.     /**
  202.      * 获取Hash中的数据
  203.      *
  204.      * @param key Redis键
  205.      * @param hKey Hash键
  206.      * @return Hash中的对象
  207.      */
  208.     public <T> T getCacheMapValue(final String key, final String hKey)
  209.     {
  210.         HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
  211.         return opsForHash.get(key, hKey);
  212.     }
  213.     /**
  214.      * 获取多个Hash中的数据
  215.      *
  216.      * @param key Redis键
  217.      * @param hKeys Hash键集合
  218.      * @return Hash对象集合
  219.      */
  220.     public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
  221.     {
  222.         return redisTemplate.opsForHash().multiGet(key, hKeys);
  223.     }
  224.     /**
  225.      * 删除Hash中的某条数据
  226.      *
  227.      * @param key Redis键
  228.      * @param hKey Hash键
  229.      * @return 是否成功
  230.      */
  231.     public boolean deleteCacheMapValue(final String key, final String hKey)
  232.     {
  233.         return redisTemplate.opsForHash().delete(key, hKey) > 0;
  234.     }
  235.     /**
  236.      * 获得缓存的基本对象列表
  237.      *
  238.      * @param pattern 字符串前缀
  239.      * @return 对象列表
  240.      */
  241.     public Collection<String> keys(final String pattern)
  242.     {
  243.         return redisTemplate.keys(pattern);
  244.     }
  245. }
复制代码
获取验证码接口流程

后端提供验证码

        我们提供一个get接口来实现该流程

  • 生存验证码信息,生成UUID并构建验证码键名
  • 生成验证码(字符or数学)
  • 将生成的验证码存入Redis缓存,并设置过期时间
  • 转换流信息写出
  • 将验证码图片转换为Base64编码格式,将UUID和Base64编码后的图片添加到响应对象并返回
  1. package com.hl;
  2. import com.google.code.kaptcha.Producer;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.util.FastByteArrayOutputStream;
  6. import org.springframework.web.bind.annotation.*;
  7. import javax.annotation.Resource;
  8. import javax.imageio.ImageIO;
  9. import java.awt.image.BufferedImage;
  10. import java.io.IOException;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. import java.util.UUID;
  14. import java.util.concurrent.TimeUnit;
  15. @Slf4j
  16. @RestController
  17. public class LoginController {
  18.     @Resource(name = "captchaProducer")
  19.     private Producer captchaProducer;
  20.     @Autowired
  21.     private RedisCache redisCache;
  22.     @GetMapping("/captchaImage")
  23.     public Result<Map<String,String>> captchaImage() {
  24.         log.info("获取验证码");
  25.         // 保存验证码信息,生成UUID并构建验证码键名
  26.         String uuid = UUID.randomUUID().toString();
  27.         String verifyKey = "captcha_codes:" + uuid;
  28.         String capStr = null, code = null;
  29.         BufferedImage image = null;
  30.         // 生成验证码
  31.         //数学运算型验证码
  32. //        String capText = captchaProducerMath.createText();
  33. //        capStr = capText.substring(0, capText.lastIndexOf("@"));
  34. //        code = capText.substring(capText.lastIndexOf("@") + 1);
  35. //        image = captchaProducerMath.createImage(capStr);
  36.         //字符型验证码
  37.         capStr = code = captchaProducer.createText();
  38.         image = captchaProducer.createImage(capStr);
  39.         //将生成的验证码存入Redis缓存,并设置过期时间
  40.         redisCache.setCacheObject(verifyKey, code, 2, TimeUnit.MINUTES);
  41.         // 转换流信息写出
  42.         FastByteArrayOutputStream os = new FastByteArrayOutputStream();
  43.         try {
  44.             ImageIO.write(image, "jpg", os);
  45.         } catch (IOException e) {
  46.             throw new RuntimeException(e);
  47.         }
  48.         //将验证码图片转换为Base64编码格式,将UUID和Base64编码后的图片添加到响应对象并返回
  49.         Map<String, String> result = new HashMap<>();
  50.         result.put("uuid", uuid);
  51.         result.put("img", Base64.encode(os.toByteArray()));
  52.         return Result.success(result);
  53.     }
  54. }
复制代码
前端吸收Base64的验证码图片

        前端发送请求后端接口,获取验证码图片的Base64信息,将其塞入img标签的src属性中。为img标签添加onclick事件,每次点击,就重新请求验证码图片。
  1. import request from '@/utils/request'
  2. export const getCodeImg = () => {
  3.     return request.get('/captchaImage');
  4. }
复制代码
  1. <script setup>
  2. //引入组件
  3. import { ref } from "vue";
  4. import { ElMessage } from "element-plus";
  5. const userDate = ref({
  6.   username: "",
  7.   password: "",
  8.   captcha: "",
  9. });
  10. // vue3-puzzle-vcode
  11. import Vcode from "vue3-puzzle-vcode";
  12. const isShow = ref(false);
  13. const onShow = () => {
  14.   isShow.value = true;
  15. };
  16. const onClose = () => {
  17.   isShow.value = false;
  18. };
  19. const onSuccess = () => {
  20.   onClose(); // 验证成功,手动关闭模态框
  21. };
  22. const imgs = [
  23.   "https://picsum.photos/200/300?random=1",
  24.   "https://picsum.photos/200/300?random=2",
  25.   "https://picsum.photos/200/300?random=3",
  26.   "https://picsum.photos/200/300?random=4",
  27.   "https://picsum.photos/200/300?random=5",
  28. ];
  29. // kaptcha
  30. import { getCodeImg } from "../api/login";
  31. const codeUrl=ref('')
  32. const getCode = async()=>{
  33.     //调用接口
  34.     let result = await getCodeImg();
  35.     codeUrl.value = "data:image/gif;base64," + result.data.img;
  36.     // loginForm.value.uuid = res.uuid;
  37. }
  38. getCode();
  39. </script>
  40. <template>
  41.   <Vcode :show="isShow" @success="onSuccess" @close="onClose" :imgs="imgs" />
  42.   <el-form
  43.     style="width: 500px; height: 40px; margin: auto; padding-top: 100px"
  44.     red="form"
  45.     :model="userDate"
  46.   >
  47.     <el-form-item label="账号">
  48.       <el-input v-model="userDate.username" placeholder="账号"></el-input>
  49.     </el-form-item>
  50.     <el-form-item label="密码">
  51.       <el-input v-model="userDate.password" placeholder="密码"></el-input>
  52.     </el-form-item>
  53.     <el-form-item label="验证码">
  54.       <el-input v-model="userDate.captcha" placeholder="验证码" class="codeInput"></el-input>
  55.     <!-- kaptcha -->
  56.     <div class="login-code">
  57.       <img :src="codeUrl" @click="getCode" class="login-code-img" />
  58.     </div>
  59.     </el-form-item>
  60.     <el-form-item>
  61.       <el-button type="primary" @click="onShow">登录</el-button>
  62.     </el-form-item>
  63.   </el-form>
  64. </template>
  65. <style lang='scss' scoped>
  66. .login-code {
  67.   width: 33%;
  68.   height: 40px;
  69.   float: right;
  70.   img {
  71.     cursor: pointer;
  72.     vertical-align: middle;
  73.   }
  74. }
  75. .login-code-img {
  76.   height: 40px;
  77.   padding-left: 12px;
  78. }
  79. .codeInput {
  80.   width: 60%;
  81. }
  82. </style>
复制代码
注: 代码未全部展示,只展示了紧张部分



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

涛声依旧在

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表