一.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
简朴例子
点击开始验证按钮弹出验证弹窗
- <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.comhttps://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,no
- properties.setProperty(KAPTCHA_BORDER, "no");
- // 验证码文本字符颜色 默认为Color.BLACK
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
- // 验证码图片宽度 默认为200
- properties.setProperty(KAPTCHA_IMAGE_WIDTH, "200");
- // 验证码图片高度 默认为50
- properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
- // 验证码文本字符大小 默认为40
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
- // KAPTCHA_SESSION_KEY
- properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
- // 验证码文本字符长度 默认为5
- properties.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.ShadowGimpy
- properties.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: 8080
- address: 127.0.0.1
- spring:
- # redis配置
- redis:
- host: localhost
- port: 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 {
- @Autowired
- private RedisConnectionFactory factory;
- @Bean
- public 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和public
- om.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;
- }
- @Bean
- public 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
- {
- @Autowired
- public 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接口来实现该流程
- 生存验证码信息,生成UUID并构建验证码键名
- 生成验证码(字符or数学)
- 将生成的验证码存入Redis缓存,并设置过期时间
- 转换流信息写出
- 将验证码图片转换为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-form
- style="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>
复制代码 注: 代码未全部展示,只展示了紧张部分
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |