当前位置: 首页 > news >正文

基于SpringBoot和Hutool工具包实现的验证码案例

目录

验证码案例

1. 需求

2. 准备工作

3. 约定前后端交互接口 

需求分析

接口定义

4. Hutool 工具介绍

5. 实现验证码

后端代码 

前端代码

6. 运行测试 


验证码案例

随着安全性的要求越来越高,目前项目中很多都会使用验证码,只要涉及到登录,绝大多数都会有验证的要求,验证码的形式也是多种多样,更复杂的图形验证码和行为验证码已经成为了更流行的趋势。

验证码的实现方式很多,可以前端实现,也可以后端实现。网上也有比较多的插件或者工具包可以使用,这里选择使用 Hutool工具包 来实现一个简单的验证码案例。完整代码见文章末尾。

1. 需求

最终实现的验证码界面如下图所示:

1. 页面生成验证码

2. 输入验证码,点击提交,验证用户输入验证码是否正确且是否超时,正确且未超时则进行页面跳转,错误或已超时则进行提示,并更换验证码

2. 准备工作

创建SpringBoot项目,引入Spring-Web-MVC和Lombok的依赖包,前端界面会在后面提供.

3. 约定前后端交互接口 

需求分析

后端需要提供两个服务:

  1. 生成验证码,并返回验证码.
  2. 校验验证码是否正确.

接口定义

1)生成验证码

请求: 

请求URL:/captcha/get

 响应:浏览器显示图片内容

浏览器给服务器发送一个 /captcha/get 请求,服务器返回一个图片,浏览器显示在页面上

2)校验验证码是否正确

请求:

请求URL:/captcha/check
请求参数:captcha=验证码字符串

响应:

true or false
根据用户输入的验证码,校验验证码是否正确,并判断验证码是否超时

4. Hutool 工具介绍

Hutool官网:https://hutool.cn/

Hutool参考文档:https://hutool.cn/docs/#/

要使用Hutool工具包,需要在pom.xml文件中添加对应的依赖,参考文档中有详细介绍:

<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version>
</dependency>

在Hutolol参考文档中找到图形验证码部分:

接下来可以就可以参考Hutool工具提供的方法,快速生成验证码,里面的介绍非常清晰,很容易看懂。此处使用如下格式验证码:

5. 实现验证码

项目目录结构如下:

后端代码 

实现接口

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hxxy.captchademo.config.CaptchaProperties;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;
import java.util.Date;@RestController
@RequestMapping("/captcha")
public class CaptchaController {@Autowiredprivate CaptchaProperties captchaProp;@RequestMapping("/get")public void getCaptcha(HttpServletResponse response, HttpSession session) {//定义图形验证码的长和宽(配置默认值)LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProp.getWidth(), captchaProp.getHeight());//细节问题,不影响程序//设置返回类型response.setContentType("image/jpeg");//静止缓存response.setHeader("Progma", "No-cache");try {//图形验证码写出,可以写出到文件,也可以写出到流lineCaptcha.write(response.getOutputStream());//同时将验证码内容和当前时间戳存储到Session中//此处Session的键可以配置成常量session.setAttribute(captchaProp.getSession().getKey(), lineCaptcha.getCode());session.setAttribute(captchaProp.getSession().getDate(), new Date());//关流response.getOutputStream().close();} catch (IOException e) {throw new RuntimeException(e);}}//验证码生效时间限制private static final long VALID_MILLIS_TIME = 60 * 1000;@RequestMapping("/check")public boolean checkCaptcha(String captcha, HttpSession session) {//保证传过来的参数是合法的if (StringUtils.hasLength(captcha)) {//根据配置的默认session信息获取key和dateString key = (String) session.getAttribute(captchaProp.getSession().getKey());Date date = (Date) session.getAttribute(captchaProp.getSession().getDate());//1.验证码正确(不区分大小写)  2.验证码还未失效return key.equalsIgnoreCase(captcha)&& System.currentTimeMillis() - date.getTime() < VALID_MILLIS_TIME;}return false;}
}

代码解析:

  1. 通过@Autowired注解注入了一个CaptchaProperties对象,这个对象是用来配置图形验证码的属性的。使用这种方式是因为代码中的有些属性可能会在别处使用,且它们都是固定的,例如图形验证码的长和宽,Session的字段名等。将这些属性封装在一个对象中,并通过读取配置文件的方式绑定属性值。

  2. 在@RequestMapping注解的getCaptcha方法中,使用Hutool包的CaptchaUtil.createLineCaptcha方法创建了一个图形验证码对象lineCaptcha,其大小由配置文件中的captchaProp.getWidth()和captchaProp.getHeight()决定。然后,将验证码内容和当前时间戳存储到HttpSession中,以便后续校验验证码的时候使用。最后,将图形验证码写出到HttpServletResponse的输出流中,以返回给前端页面显示。

  3. 在@RequestMapping注解的checkCaptcha方法中,首先判断传入的验证码参数是否合法。如果合法,则从HttpSession中获取存储的验证码内容和时间戳信息,并进行比较。如果验证码正确且未过期,则返回true,否则返回false。

CaptchaProperties类的实现和配置文件(.yml)信息如下:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "captcha")
public class CaptchaProperties {private Integer width;private Integer height;private Session session; //使用自定义的Session类@Datapublic static class Session {private String key;private String date;}
}
spring:application:name:captcha-democaptcha:width: 200height: 100session:key: CAPTCHA_SESSION_KEYdate: CAPTCHA_SESSION_DATE

此处还没有前端代码,但是已经可以先测试了,通常写好一个接口就可以测试一下。

启动项目,再访问 http://127.0.0.1:8080/captcha/get  显示验证码图片如下:

通过 Fiddler 进行抓包,HTTP请求和响应数据如下,图片就在响应的body部分:

前端代码

注意前端代码要放在resources的static目录下

index.html(重点关注script标签内的代码):

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><title>验证码</title><style>#inputCaptcha {height: 30px;vertical-align: middle;}#verificationCodeImg {vertical-align: middle;}#checkCaptcha {height: 40px;width: 100px;}</style>
</head><body>
<h1>输入验证码</h1>
<div id="confirm"><input type="text" name="inputCaptcha" id="inputCaptcha"><img id="verificationCodeImg" src="/captcha/get" style="cursor: pointer;" title="看不清?换一张"/><input type="button" value="提交" id="checkCaptcha">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>//点击图片,切换验证码$("#verificationCodeImg").click(function () {//$(this).hide().attr('src', '/captcha/get?dt=' + new Date().getTime()).fadeIn();//使用attr()方法修改src属性值,获取一个新的验证码图片,后面添加一个时间戳参数来保证每次请求的验证码图片都是不同的$(this).attr('src', '/captcha/get?dt=' + new Date().getTime());});//点击提交按钮,进行验证码校验$("#checkCaptcha").click(function () {$.ajax({url: "/captcha/check",type: "post",data: {captcha: $("#inputCaptcha").val()},success: function (result) {if (result) {location.href = "success.html";} else {alert("验证码错误或已超时");//验证码错误,重新生成验证码$("#verificationCodeImg").attr('src', '/captcha/get?dt=' + new Date().getTime());$("#inputCaptcha").val("");}}});});</script>
</body></html>

JavaScript代码中主要包含两部分逻辑:

  1. 点击图片,切换验证码: 当id为"verificationCodeImg"的图片被点击时,会触发click事件的回调函数。回调函数通过修改图片的src属性,向后端发送一个请求来获取新的验证码图片,并使用当前时间戳作为参数,以确保每次请求的验证码图片都是不同的。最后,将获取到的新图片显示出来。

  2. 点击提交按钮,进行验证码校验: 当id为"checkCaptcha"的按钮被点击时,会触发click事件的回调函数。回调函数通过使用jQuery的ajax方法发送一个POST请求到"/captcha/check"接口,并传递了一个名为"captcha"的参数,该参数的值为id为"inputCaptcha"的输入框中用户输入的验证码。

    在请求成功后的回调函数中,会根据后端返回的结果(result)进行处理。如果校验成功,则跳转到"success.html"页面;如果校验失败,则弹出一个提示框显示"验证码错误或已超时",并重新生成新的验证码图片并清空输入框中的验证码。

success.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>验证成功页</title>
</head>
<body><h1>验证成功</h1>
</body>
</html>

6. 运行测试 

启动项目,浏览器访问 http://127.0.0.1:8080/index.html 或 http://localhost:8080/index.html

输入错误的验证码: 

提示正确,且验证码能正确刷新,超时同样会提示以上错误。且点击验证码图片时,会重新生成验证码。

输入正确的验证码:

验证成功,页面正确跳转,测试完成。

完整代码:https://gitee.com/lv-jiacong/Java-EE/tree/master/captcha-demo/src

相关文章:

基于SpringBoot和Hutool工具包实现的验证码案例

目录 验证码案例 1. 需求 2. 准备工作 3. 约定前后端交互接口 需求分析 接口定义 4. Hutool 工具介绍 5. 实现验证码 后端代码 前端代码 6. 运行测试 验证码案例 随着安全性的要求越来越高&#xff0c;目前项目中很多都会使用验证码&#xff0c;只要涉及到登录&…...

python-找出四位数中的玫瑰花数

【问题描述】玫瑰花数指一个n位数&#xff08;n>4),其每位上的数字的n次幂之和等于本身。 请求出所有四位数中的玫瑰花数 【输入形式】 【输出形式】 【样例输入】 【样例输出】1634 8208 9474 【样例说明】 【评分标准】 完整代码如下&#xff1a; for n in ra…...

Linux-命令上

at是一次性的任务&#xff0c;crond是循环的定时任务 如果 cron.allow 文件存在&#xff0c;只有在文件中出现其登录名称的用户可以使用 crontab 命令。root 用户的登录名必须出现在 cron.allow 文件中&#xff0c;如果这个文件存在的话。系统管理员可以明确的停止一个用户&am…...

青鸟云报修系统:实现高效、便捷的维修申请处理

在日常生活和工作中&#xff0c;故障报修难免会遇到&#xff0c;售后报修服务则成为了解决问题的关键。纸质化售后报修维修申请单&#xff0c;作为报修流程中的重要一环&#xff0c;在一定程度上能够记录和追踪售后报修维修流程&#xff0c;但在实际操作过程中却存在着诸多弊端…...

Python解析网页

目录 1、Beautiful Soup 2、解析数据 3、遍历文档树 4、搜索文档树 一、Beautiful Soup 1、什么是Beautiful Soup 定义&#xff1a;Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库. 功能&#xff1a;它能够通过你喜欢的转换器实现惯用的文档导航,查找,修…...

IDEA连接MySQL后如何管理数据库

上一节讲解了IDEA如何连接MySQL数据库管理系统&#xff0c;接下来我们就可以在IDEA里使用MySQL来管理数据库了。那么如果我们现在还没有创建需要的数据库怎么办&#xff1f;本节就来教大家如何在IDEA连接MySQL后管理数据库(创建/修改/删除数据库、创建/修改/删除表、插入/更新/…...

linux新机快速配置ssh

配置SSH以实现证书登录 要配置新的Linux机器以实现证书登录&#xff0c;您需要执行以下步骤&#xff1a; 安装SSH服务器&#xff1a; sudo apt-get install openssh-server修改SSH端口&#xff08;可选&#xff09;&#xff1a; SSH配置文件&#xff08;通常位于/etc/ssh/sshd…...

使用elementUI的form表单校验时,错误提示位置异常解决方法

问题 最近在做项目时遇到一个问题&#xff0c;使用elementUI的Descriptions 描述列表与form表单校验时&#xff0c;遇到校验信息显示的位置不对&#xff0c;效果如图&#xff1a; 期望显示在表格中。 效果 代码 html <el-form :model"form":rules"rules…...

Android面试题之Kotlin常见集合操作技巧

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 list 创建和修改 不可变list,listOf var list listOf("a","d","f") println(list.getOrElse(3){"Unkn…...

网络拓扑—DNS服务搭建

文章目录 DNS服务搭建网络拓扑配置网络DNSPC 安装DNS服务配置DNS服务创建正向查找区域创建反向查找区域创建子域名 PC机DNS域名解析 DNS服务搭建 网络拓扑 为了节省我的U盘空间&#xff0c;没有用路由器&#xff0c;所以搭建的环境只要在同网段即可。 //交换机不用考虑 DNS&a…...

Mybatis-Plus笔记

1.MP基础 1.1 MP常见注解 TableName(“指定表明”) TableName("tb_user") // 指定表名 Data NoArgsConstructor AllArgsConstructor Builder public class User {private Long id;private String userName;private String password;private String name;private I…...

“高考钉子户”唐尚珺决定再战2024年高考

“高考钉子户”唐尚珺决定在2024年再次参加高考&#xff0c;这个选择确实很特别也很有趣。十几年连续参加高考&#xff0c;他已经积累了大量的备考经验和应试技巧。这样的经验对于高考辅导机构来说无疑是非常宝贵的资源&#xff0c;他如果选择去辅导机构当老师&#xff0c;应该…...

Hive安装教程

前置条件:hadoop&mysql docker容器安装mysql-CSDN博客 以下的/opt/bigdata目录根据自己实际情况更改 1.上传hive包并解压 tar -zxvf apache-hive-3.1.3-bin.tar.gz -C /opt/bigdata/ 2.修改路径 mv /opt/bigdata/apache-hive-3.1.3-bin/ hive cd /opt/bigdata/hive/…...

使用Python Tkinter创建GUI应用程序

大家好&#xff0c;当我们谈及使用Python Tkinter创建GUI应用程序时&#xff0c;我们涉及的不仅是技术和代码&#xff0c;更是关于创造力和用户体验的故事。Tkinter作为Python标准库中最常用的GUI工具包&#xff0c;提供了丰富的功能和灵活的接口&#xff0c;让开发者能够轻松地…...

使用 RT 矩阵进行 3D 点云变换详解(基于 PCL 和 Eigen 库)

在 3D 点云处理中&#xff0c;RT 矩阵是一个常用的工具&#xff0c;用于对点云进行旋转和平移操作。本文将详细介绍 RT 矩阵的概念&#xff0c;并通过一个示例程序演示如何基于 PCL 和 Eigen 库将一帧点云进行矩阵变换再输出。 本教程的示例代码和点云数据可在 GitHub 下载。 什…...

CTFHUB技能树——SSRF(二)

目录 上传文件 ​FastCGI协议 Redis协议 上传文件 题目描述&#xff1a;这次需要上传一个文件到flag.php了.祝你好运 index.php与上题一样&#xff0c;使用POST请求的方法向flag.php传递参数 //flag.php页面源码 <?phperror_reporting(0);if($_SERVER["REMOTE_ADDR&…...

Vue3实现简单的瀑布流效果,可抽离成组件直接使用

先来看下效果图&#xff1a; 瀑布流中的内容可进行自定义&#xff0c;这里的示例图是通过不同背景颜色的展示进行区分&#xff0c;每个瀑布流中添加了自定义图片和文字描述。 实现方式&#xff1a; 1.建立子组件&#xff08;可单独抽离&#xff09;写出瀑布流的样式 文件名为…...

【已解决】C#如何消除Halcon上一次显示窗口的涂层

前言 在通过C#进行封装Halcon的时候发现一个问题&#xff0c;就是如果我重新去标定一个图像的时候不能把上一次的清掉&#xff0c;然后之前的会覆盖掉原来的&#xff0c;这个确实是这样&#xff0c;但是如果说现在的图像面积比之前的小的那么就没有任何效果显示&#xff0c;因…...

XShell-连接-Centos 7

XShell 连接Centos 7 一.准备 安装XShell XShell下载地址&#xff1a; 在虚拟机上安装Centos 7&#xff0c;具体操作自行学习 二.Centos 7的准备 1.网络适配器修改为NAT 2.获取IP 输入命令&#xff1a; ip addr我的Centos 7对外IP为192.168.174.129 三.XShell连接Cento…...

vue3 组件刷新

在 Vue 3 中&#xff0c;如果你想刷新一个组件&#xff0c;有几种方法可以实现。 使用 key 属性: 当你想要强制重新渲染一个组件时&#xff0c;你可以为其添加一个独特的 key 属性。当 key 属性的值改变时&#xff0c;Vue 会强制组件重新创建。 <template> <MyComp…...

Java进阶学习笔记14——模板方法设计模式

面试和看源码。 谈到设计模式&#xff1a; 1、解决了什么问题&#xff1f; 2、怎么写&#xff1f; 模板方法设计模式解决了什么问题&#xff1f; 解决方法中存在重复代码的问题。 写法&#xff1a; 1&#xff09;定义一个抽象类&#xff1a; 2&#xff09;在里面定义两个方…...

Centos7静态路由和动态路由

路由&#xff0c;即路由选择&#xff08;Routing&#xff09;&#xff0c;是指在计算机网络中选择数据传输路径的过程。路由器&#xff08;Router&#xff09;是执行路由选择功能的网络设备。路由的主要目的是在复杂的网络结构中&#xff0c;选择最佳路径将数据包从源节点传递到…...

戴尔(Dell)服务器运行状况监控

戴尔&#xff08;Dell&#xff09;服务器因其加速的性能、增强的自动化和简化的管理而受到全球许多组织的青睐&#xff0c;许多组织将其业务关键应用程序和功能放在戴尔&#xff08;Dell&#xff09;服务器中&#xff0c;因此&#xff0c;有效的戴尔&#xff08;Dell&#xff0…...

vue3文档v-model.xxxx自定义修饰符

...

微信小程序毕业设计-智慧旅游平台系统项目开发实战(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…...

抖音小店新规又来了!平台下调了两项门槛,惊掉商家下巴!

大家好&#xff0c;我是电商糖果 平台这几年为了快速发展电商项目&#xff0c;一直在向商家释放友好政策&#xff0c;目的就是为了吸引更多的商家入驻。 这不官方5月30日起下调了两个门槛&#xff0c;让不少商家大呼不可思议。 第一个就是保证金下调。 平台按照商家经营类目…...

【启程Golang之旅】运算符与流程控制讲解

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…...

Docker: exec命令浅析

简介 Docker exec命令是Docker提供的一个强大工具&#xff0c;用于在正在运行的容器中执行命令。在此将介绍Docker exec命令的用法和示例&#xff0c;帮助大家更好地理解和使用这个命令。 Docker是一种流行的容器化平台&#xff0c;允许用户在容器中运行应用程序。有时候&#…...

c++的查漏补缺 1、函数指针

今天写链表的插入排序时遇到了一个问题 void InsertionSortList(ListNode* head, int n){if (!head||!head->next) return nullptr;auto dummy new ListNode(-1);dummy->next head;auto pre head;auto cur head->next;while (cur ! NULL){auto tmp dummy;if (pre…...

uniapp+php服务端实现苹果iap内购的消耗性项目和非续期订阅项目,前后端代码加逻辑分析

前言&#xff1a;公司的项目app在上架苹果商店时发现人家要求里面的部分购买项目必须使用iap购买的方式&#xff0c;使用原本的微信支付方式审核不给通过&#xff0c;无奈只能重新研究这个东西。做起来还是有点麻烦&#xff0c;主要是网上的文章很少&#xff0c;不能直接硬抄。…...