网站实现验证码功能

一、验证码

一般来说,网站在登录的时候会生成一个验证码来验证是否是人类还是爬虫,还有一个好处是防止恶意人士对密码进行爆破。

二、流程图

三、详细说明

3.1 后端生成验证码

@Override
public Result<Map<String, String>> getVerificationCode() {// HuTool 定义图形验证码的长和宽, 验证码的位数,干扰线的条数// 线段干扰的验证码LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(116, 36, 4, 50);String uuid = UUID.randomUUID().toString();String verificationCodeKey = "VerificationCode:" + uuid;// 存到 redis 中ValueOperations<String, String> ops = redisTemplate.opsForValue();ops.set(verificationCodeKey, lineCaptcha.getCode());// 设置 15 分钟的过期时间redisTemplate.expire(verificationCodeKey, 15, TimeUnit.MINUTES);Map<String, String> map = new HashMap<>(2);map.put("verificationCodeBase64", lineCaptcha.getImageBase64());map.put("uuid", uuid);return Result.success(map);
}

记得设置验证码过期时间,否则每一次生成验证码都会在 redis 里面产生数据,造成内存浪费。
返回给前端的 json

{"code": 200,"msg": "操作成功","data": {"uuid": "bc814884-fffb-4943-834a-40cc92decfa6","verificationCodeBase64": "iVBORw0KGgoAAAANSUhEUgAAAHQAAAAkCAYAAABYFB7QAAAFtUlEQVR4Xu3YfUxVdRjAcW0zM6atSX84X1JhleMPI6VmtcxexFZs5qq5/mhNpxKV06TMiQrpVssxopClZr7QdFCycutFpmn4QhgkA+J2GaK8eUWUCxeIe70vT/f33J2zc557zr33nPM7B1C+2zPvPc9BNz4751zvGBjttmoMPTCavrzxc3CGOgR9p/klepxbr/W+Rw8N2wq3ZeMYaahhxSuUoeqFdTRPxFHLCtS3en8Xh5ZxLlM2t3Nht9w3FteFTawJsEq4DHXem/eEjZkdyX8+puEN7c5ZD+kHNokTa2/f/7Fs9BQGyisprhRYuFrnl/yGQ4HNRlZr3MI8cXgCU1w16E83bpe9Z+kBNg2URmGFBNjhlBSXjVlRXIaqBKsly0CjNRxhhXgCv3rykjhqGUFF0H/yxmsaXvmvJOOMtHjhFqUVgO3uVTEhx5pmUNuuB+jfoTsK+tOGkzh3Qr0lFxCTjTSjuDHfcrvr9iGoq+kYXXFPgB2OuCsnpNFDmnOVVsO/cemKoEaLCXSwqxYavpwEV09k0JXp8cId15uKYzRDoD4/XM8qBdv41SKm5aABvxcuFc0H++7p4Pf00rUpJazbKhshs2CffPlF2ftI6QXtL6uH5uRsEfHygh1DA3qjKhdvtc76g3RlOPoMVYsCU2itBQIAcZVrIX73fpiS8wvM3HgWZqz7GR5atQvs1wbo6bCsY6z4moK2LUzEiZZ4RU5YA52ZxRAYvGU9qO+/ruCHoHhoOjg3+Fvw0bXhYgVVSw9wv9sHKw80wNTMM4ozbcNpSF7+Pv2xqAmwasDsNtu29Ctw17bh+7FnvhVB2WteRQR1nM7Eq7PHdhjfZ8EzOGqlTdf2izAKqqe1R+wIN2dLBewt74AOpxvcXj/YrvZDepENdwmbzkHK0tc13YppFNZjd0i2oaRXKEOloydVUJ/bCbaCyWDfMyN4cXpkOwE2Em4sRQPtnfUBPWSoi60uBEsMgjFAGrsVC1fv5tImuuaepbfcrr924tV5vSLytxZGcKOBshgqL9icY82I9dmvV+hKrK69D895fMcFuuKedaDB52Xj3tnQkB8H3oFOulVNK6waqMN/Fz3EBTU17yJi1bT20RVsHrst5uGVZaD9rafx6rzywxLxWNe0BZIz+KQGylJCNdrc7D8R1DWo/wNeR9kUHB5ZBuo4tR5Bb9YUyo7zRo0EymKoPGEf/Ogsgvr8AbqSlfrwCtkoJcAaAbYMtPGbBAS95Qp9xJbGUHnBUtD8Nd9JtqHW5D0njtEeyTqPoH1ubVcoBVZC1gNsCaj7Rj1iNh16jK5k8UAVQNsLs3BYDFUJliXF1QO8aGc1gta2hz9Dha67PHhO8ieV+P7dtqdxtBYLrCWg3bV7EbSjjO8/pBS9QgVYYdRghbQCbyhuRKz8E610JfZ9VSees/qQTXZcgNWDq5YloOwLeAbaXfM1XXGPgtIocLSi4Z5v6kGspK0V0O500zUMeHyw8PMqPOd4/U265p4loJeLn0XQ/tZTdMW9aKA0Lbhqrdgf+uJg3vZKOFrdCc4BL37qLW90wgu5f+NuWWEt/TFTsgTUvmcmgnq67XTFPSXQpJRZsuGda9CLYAxOadhzlj1Hrch00Lh9BVDzxb0I6ve4pCtTUgKlUWAtyMltcYrzaMtEOFx5DWHZd7pTPyzHW23u8Rb88t6qTAcVYrBszM0fAm1JoYuwls/OxuEZRU44VYLDXlvdkUk/ysZIiqBCAqwpuL4bIdDWRXSjmhpsYfUJ2RhJgFWqc/F9OGZnBDciqDRusEFICLgh0LMnBOoI/096tNRghSiwUWRaJNi6pFdwhqqYQfkUvM22PCU+O9kE+o7Sk0ZMAiybjD+yxWEJsFYDWwvqdYC/PS2I+kTwzyXBq3QfPWPEJr1qpbgU2EiTlyXgRMpa0DukLeWJsuFdJNhR0BGcEuwo6G3W/2buccxVrdRAAAAAAElFTkSuQmCC"}
}

Base64 是一种用于将二进制数据编码为 ASCII 字符的编码方法,我们这边用这个编码传递验证码图片,数据在 verificationCodeBase64

3.2 前端生成验证码图片

3.2.1 获取验证码 Base64 并且拼接
const updateVerificationCodeImage = async () => {// 图像类型const imageType = 'image/png';const res = await userGetVerificationCodeApi();if (res.data) {if (res.data.data) {verificationCodeBase64.value = res.data.data.verificationCodeBase64;uuid.value = res.data.data.uuid;// 拼接 Base64 图像数据verificationCodeImageSrc.value = `data:${imageType};base64,${verificationCodeBase64.value}`;}}
};
3.2.2 渲染到页面上
<div class="verificationCode-class"><img :src="verificationCodeImageSrc" alt="验证码加载失败" /><el-link class="mx-1" @click="updateVerificationCodeImage">看不清楚, 换一张</el-link>
</div>

3.3 前端用户点击登录

登录表单的数据加上 uuid 和验证码,确保唯一性。

const form = reactive({username: '',password: '',uuid: '',verificationCode: '',
});

3.4 后端验证用户输入的验证码是否正确

@Override
public Result<AppUserLoginVO> userLogin(AppUserLoginDTO appUserLoginDTO) {if (Objects.nonNull(appUserLoginDTO)) {// 先对验证码进行核对ValueOperations<String, String> ops = redisTemplate.opsForValue();String uuid = appUserLoginDTO.getUuid();String verificationCode = appUserLoginDTO.getVerificationCode();String verificationCodeKey = "VerificationCode:" + uuid;// redis 里面存的验证码String redisVerificationCode = ops.get(verificationCodeKey);if (!Objects.equals(verificationCode, redisVerificationCode)) {// 用户填入的验证码与 redis 中的不相同return Result.success(new AppUserLoginVO(), "登录失败,验证码错误");} else {// 相同ops.getOperations().delete(verificationCodeKey);}}
}

四、结果

五、参考资料

  • hutool-图形验证码

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

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

相关文章

LeetCode | 100. 相同的树

LeetCode | 100. 相同的树 OJ链接 判断两个节点是否等于空&#xff0c;两个都等于空就直接返回true如果一个等于空&#xff0c;另一个不等于空&#xff0c;说明false然后再判断两个树的值是否相等最后递归p的左&#xff0c;q的左&#xff0c;p的右&#xff0c;q的右 bool isS…

计算机网络TCP篇①

目录 一、TCP 基本信息 1.1、TCP 的头格式 1.2、什么是 TCP 1.3、什么是 TCP 连接 1.4、TCP 与 UDP 的区别 1.2、TCP 连接建立 1.2.1、TCP 三次握手的过程 1.2.2、为什么是三次握手&#xff1f;不是两次&#xff1f;四次&#xff1f;&#xff08;这个问题真是典中典&am…

山西电力市场日前价格预测【2023-12-03】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-12-03&#xff09;山西电力市场全天平均日前电价为360.65元/MWh。其中&#xff0c;最高日前电价为517.29元/MWh&#xff0c;预计出现在00:30。最低日前电价为0.00元/MWh&#xff0c;预计出…

nodejs微信小程序+python+PHP金融产品销售系统的设计与实现-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

网络通信原理,进制转化总结

来源&#xff0c;做个笔记&#xff0c;讲的还蛮清楚通信原理-2.5 数据封装与传输05_哔哩哔哩_bilibili ip地址范围

【数据结构】环形队列

环形队列 1. 定义 环形队列就是将队列在逻辑上看作环形结构、物理上仍是数组形式存储的一种数据结构。 其实现主要分为两种情况&#xff1a; 浪费空间法记录空间法 2. 实现 实现要考虑的是成员变量 2.1 记录空间法 使用used标识当前存储了多少元素&#xff0c;如果为空&a…

4个Pycharm高效插件

大家好&#xff0c;Pycharm是Python最受欢迎的集成开发环境之一&#xff0c;它具有良好的代码助手、漂亮的主题和快捷方式&#xff0c;使编写代码变得简单快捷。话虽如此&#xff0c;开发者仍可以通过使用一些插件来提高在Pycharm中编写Python代码的效率和乐趣&#xff0c;在市…

Java核心知识点整理大全27-笔记(已完结)

30. 云计算 30.1.1. SaaS SaaS 是 Software-as-a-Service&#xff08;软件即服务&#xff09; 30.1.2. PaaS PaaS 是 Platform-as-a-Service 的缩写&#xff0c;意思是平台即服务。 把服务器平台作为一种服务提供的 商业模式。通过网络进行程序提供的服务称之为 SaaS(Softw…

springBoot整合quartz

springBoot整合quartz 文章目录 springBoot整合quartz 导坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency>定义任务&#xff0c;不需要定义为Bean&#x…

某公司前端笔试题(12.30)

1、对象数组去重&#xff1a; 数组去重&#xff1a; const a[{a:1,b:2},{a:2},{a:2},{a:1,c:3},{b:2,a:1}] 结果&#xff1a;[{a:1,b:2},{a:2},{a:1,c:3}] // 判断两个对象的属性值是否一致 const a [{ a: 1, b: 2 }, { a: 2 }, { a: 2 }, { a: 1, c: 3 }, { b: 2, a: 1 }] co…

LinkedList详解

LinkedList详解 LinkedList是List接口的一个主要的实现类之一&#xff0c;基于链表的实现。以java8为例来了解一下LinkedList的源码实现 继承关系 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>,…

前端大文件上传webuploader(react + umi)

使用WebUploader还可以批量上传文件、支持缩略图等等众多参数选项可设置&#xff0c;以及多个事件方法可调用&#xff0c;你可以随心所欲的定制你要的上传组件。 分片上传 1.什么是分片上传 分片上传&#xff0c;就是将所要上传的文件&#xff0c;按照一定的大小&#xff0c;将…