欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 基于springboot Vue3的两种图形验证码工具——vue3-puzzle-vcode纯前端防人机图形滑动验证码和kaptcha图片文字验证码

基于springboot Vue3的两种图形验证码工具——vue3-puzzle-vcode纯前端防人机图形滑动验证码和kaptcha图片文字验证码

2025/2/23 14:37:02 来源:https://blog.csdn.net/web13688565871/article/details/144421967  浏览:    关键词:基于springboot Vue3的两种图形验证码工具——vue3-puzzle-vcode纯前端防人机图形滑动验证码和kaptcha图片文字验证码

一.vue3-puzzle-vcode

Vue 纯前端的拼图人机验证、右滑拼图验证

官网:

vue3-puzzle-vcode - npm (npmjs.com)[这里是图片001]https://www.npmjs.com/package/vue3-puzzle-vcode

1.1基本使用步骤

安装

npm install vue-puzzle-vcode --save

简单例子

点击开始验证按钮弹出验证弹窗

<template><Vcode :show="isShow" @success="onSuccess" @close="onClose"/><button @click="onShow">开始验证</button>
</template><script setup>import { ref } from "vue";import Vcode from "vue3-puzzle-vcode";const isShow = ref(false);const onShow = () => {isShow.value = true;};const onClose = () => {isShow.value = false;};const onSuccess = () => {onClose(); // 验证成功,手动关闭模态框};
</script>

注:更多参数信息设置请参考官网文档

二.kaptcha

kaptcha 是谷歌开源的非常实用的验证码生成工具,基于SimpleCaptcha的开源项目。使用Kaptcha 生成验证码十分简单并且参数可以进行自定义。只需添加jar包配置下就可以使用,通过配置,可以自己定义验证码大小、颜色、显示的字符等等。

官网:code.google.com[这里是图片004]https://code.google.com/p/kaptcha/

验证码的一般流程

后端:

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

前端:

  • 进入登录/注册页面时,获取验证码图片
  • 提供刷新验证码的动作,防止出现用户难以辨识的识别码

2.1基本的使用步骤

导入POM依赖
<!-- Kaptcha 依赖(验证码) --><dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version></dependency>
KaptchaConfig配置类

该配置类用于给验证码的设置提供配置,如宽高,颜色等等

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Properties;import static com.google.code.kaptcha.Constants.*;/*** 验证码配置*/
@Configuration
public class KaptchaConfig {@Bean(name = "captchaProducer")public DefaultKaptcha getKaptchaBean() {DefaultKaptcha defaultKaptcha = new DefaultKaptcha();Properties properties = new Properties();// 是否有边框 默认为true 我们可以自己设置yes,noproperties.setProperty(KAPTCHA_BORDER, "no");// 验证码文本字符颜色 默认为Color.BLACKproperties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");// 验证码图片宽度 默认为200properties.setProperty(KAPTCHA_IMAGE_WIDTH, "200");// 验证码图片高度 默认为50properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");// 验证码文本字符大小 默认为40properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");// KAPTCHA_SESSION_KEYproperties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");// 验证码文本字符长度 默认为5properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpyproperties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");Config config = new Config(properties);defaultKaptcha.setConfig(config);return defaultKaptcha;}
}
整合Redis

Redis是一个开源的内存数据库,属于NoSQL数据库的一种。它以高性能、支持丰富的数据结构、持久化特性、复制、集群以及发布/订阅等特性而闻名。

使用Redis给验证码设置有效期

引入依赖

<!-- redis 缓存操作 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

配置yml文件

server:port: 8080address: 127.0.0.1
spring:#  redis配置redis:host: localhostport: 6379
#spring事务管理日志
logging:level:org.springframework.jdbc.support.JdbcTransactionManager: debug

Redis配置类

package com.hl;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Autowiredprivate RedisConnectionFactory factory;@Beanpublic RedisTemplate<String, Object> redisTemplate() {//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常//om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);jackson2JsonRedisSerializer.setObjectMapper(om);RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer()); //指定Redis的Key序列化方式template.setValueSerializer(jackson2JsonRedisSerializer); //指定Value的序列化方式template.setHashKeySerializer(jackson2JsonRedisSerializer); //执行Hash的Key的序列化方式template.setHashValueSerializer(jackson2JsonRedisSerializer); //指定Hash的Value的序列化方式template.setDefaultSerializer(new StringRedisSerializer());template.afterPropertiesSet();return template;}@Beanpublic ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {return redisTemplate.opsForValue();}}

Redis工具类(整合Redis的一些操作)

package com.hl;import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;/*** spring redis 工具类***/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值* @param timeout 时间* @param timeUnit 时间颗粒度*/public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @param unit 时间单位* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/*** 获取有效时间** @param key Redis键* @return 有效时间*/public long getExpire(final String key){return redisTemplate.getExpire(key);}/*** 判断 key是否存在** @param key 键* @return true 存在 false不存在*/public Boolean hasKey(String key){return redisTemplate.hasKey(key);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** @param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}/*** 删除集合对象** @param collection 多个对象* @return*/public boolean deleteObject(final Collection collection){return redisTemplate.delete(collection) > 0;}/*** 缓存List数据** @param key 缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long setCacheList(final String key, final List<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** @param key 缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet){BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()){setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 缓存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap){if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** @param key Redis键* @param hKey Hash键* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** @param key Redis键* @param hKey Hash键* @return Hash中的对象*/public <T> T getCacheMapValue(final String key, final String hKey){HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 获取多个Hash中的数据** @param key Redis键* @param hKeys Hash键集合* @return Hash对象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 删除Hash中的某条数据** @param key Redis键* @param hKey Hash键* @return 是否成功*/public boolean deleteCacheMapValue(final String key, final String hKey){return redisTemplate.opsForHash().delete(key, hKey) > 0;}/*** 获得缓存的基本对象列表** @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(final String pattern){return redisTemplate.keys(pattern);}
}
获取验证码接口流程
后端提供验证码

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

  1. 保存验证码信息,生成UUID并构建验证码键名

  2. 生成验证码(字符or数学)

  3. 将生成的验证码存入Redis缓存,并设置过期时间

  4. 转换流信息写出

  5. 将验证码图片转换为Base64编码格式,将UUID和Base64编码后的图片添加到响应对象并返回

    package com.hl;

    import com.google.code.kaptcha.Producer;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.util.FastByteArrayOutputStream;
    import org.springframework.web.bind.annotation.*;

    import javax.annotation.Resource;
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    import java.util.concurrent.TimeUnit;

    @Slf4j
    @RestController
    public class LoginController {

    @Resource(name = "captchaProducer")
    private Producer captchaProducer;
    @Autowired
    private RedisCache redisCache;@GetMapping("/captchaImage")
    public Result<Map<String,String>> captchaImage() {log.info("获取验证码");// 保存验证码信息,生成UUID并构建验证码键名String uuid = UUID.randomUUID().toString();String verifyKey = "captcha_codes:" + uuid;String capStr = null, code = null;BufferedImage image = null;// 生成验证码//数学运算型验证码
    

    // String capText = captchaProducerMath.createText();
    // capStr = capText.substring(0, capText.lastIndexOf(“@”));
    // code = capText.substring(capText.lastIndexOf(“@”) + 1);
    // image = captchaProducerMath.createImage(capStr);

        //字符型验证码capStr = code = captchaProducer.createText();image = captchaProducer.createImage(capStr);//将生成的验证码存入Redis缓存,并设置过期时间redisCache.setCacheObject(verifyKey, code, 2, TimeUnit.MINUTES);// 转换流信息写出FastByteArrayOutputStream os = new FastByteArrayOutputStream();try {ImageIO.write(image, "jpg", os);} catch (IOException e) {throw new RuntimeException(e);}//将验证码图片转换为Base64编码格式,将UUID和Base64编码后的图片添加到响应对象并返回Map<String, String> result = new HashMap<>();result.put("uuid", uuid);result.put("img", Base64.encode(os.toByteArray()));return Result.success(result);
    }
    

    }

前端接收Base64的验证码图片

前端发送请求后端接口,获取验证码图片的Base64信息,将其塞入img标签的src属性中。为img标签添加onclick事件,每次点击,就重新请求验证码图片。

import request from '@/utils/request'
export const getCodeImg = () => {return request.get('/captchaImage');
}<script setup>
//引入组件
import { ref } from "vue";
import { ElMessage } from "element-plus";
const userDate = ref({username: "",password: "",captcha: "",
});// vue3-puzzle-vcode
import Vcode from "vue3-puzzle-vcode";
const isShow = ref(false);
const onShow = () => {isShow.value = true;
};
const onClose = () => {isShow.value = false;
};
const onSuccess = () => {onClose(); // 验证成功,手动关闭模态框
};
const imgs = ["https://picsum.photos/200/300?random=1","https://picsum.photos/200/300?random=2","https://picsum.photos/200/300?random=3","https://picsum.photos/200/300?random=4","https://picsum.photos/200/300?random=5",
];// kaptcha 
import { getCodeImg } from "../api/login";
const codeUrl=ref('')
const getCode = async()=>{//调用接口let result = await getCodeImg();codeUrl.value = "data:image/gif;base64," + result.data.img;// loginForm.value.uuid = res.uuid;
}
getCode();</script>
<template><Vcode :show="isShow" @success="onSuccess" @close="onClose" :imgs="imgs" /><el-formstyle="width: 500px; height: 40px; margin: auto; padding-top: 100px"red="form":model="userDate"><el-form-item label="账号"><el-input v-model="userDate.username" placeholder="账号"></el-input></el-form-item><el-form-item label="密码"><el-input v-model="userDate.password" placeholder="密码"></el-input></el-form-item><el-form-item label="验证码"><el-input v-model="userDate.captcha" placeholder="验证码" class="codeInput"></el-input><!-- kaptcha --><div class="login-code"><img :src="codeUrl" @click="getCode" class="login-code-img" /></div></el-form-item><el-form-item><el-button type="primary" @click="onShow">登录</el-button></el-form-item></el-form>
</template><style lang='scss' scoped>
.login-code {width: 33%;height: 40px;float: right;img {cursor: pointer;vertical-align: middle;}
}
.login-code-img {height: 40px;padding-left: 12px;
}
.codeInput {width: 60%;
}
</style>

注: 代码未全部展示,只展示了主要部分

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词