推荐框架 基于SpringBoot3+Vue3前后端分离的Java快速开发框架 项目简介:基于 JDK 17、Spring Boot 3、Spring Security 6、JWT、Redis、Mybatis-Plus、Knife4j等构建后端,基于Vue 3、Element-Plus 、TypeScript等构建前端的分离单体权限管理系统。 项目地址: 后端: gitee: https://gitee.com/harry-tech/harry.git gitcode: https://gitcode.com/harry-tech/harry.git 前端: gitee: https://gitee.com/harry-tech/harry-vue.git https://gitcode.com/harry-tech/harry-vue.git 觉着有帮助,给个Star再走呗 公众号搜“Harry技术”,关注我,带你看不一样的人间烟火!
在整合技术框架的时候,想找一个图形验证码相关的框架,看到很多验证码不在更新了或者是在中央仓库下载不下来,还需要多引入依赖。后面看到了Hutool 图形验证码(Hutool-captcha)中对验证码的实现,提供了:线段干扰验证码、圆圈干扰验证码、扭曲干扰验证码以及自定义验证码。就此验证码在项目中的使用展开说明。
1. 生成验证码,点击图片可进行刷新
2. 输入验证码,点击提交,验证用户输入验证码是否正确
首先创建项目这里使用的Spring boot 3 + JDK17,并引入相关依赖
pom.xml
<properties>
<java.version>17</java.version>
<hutool.version>5.8.26</hutool.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<!-- 注意这里是import -->
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
如果你想像Spring-Boot一样引入Hutool,再由子模块决定用到哪些模块,你可以在父模块中加入:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<!-- 注意这里是import -->
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在子模块中就可以引入自己需要的模块了:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
</dependency>
使用import的方式,只会引入hutool-bom内的dependencyManagement的配置,其它配置在这个引用方式下完全不起作用。
如果你引入的模块比较多,但是某几个模块没用,你可以:
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<!-- 加不加这句都能跑,区别只有是否告警 -->
<type>pom</type>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-system</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
这个配置会传递依赖hutool-bom内所有dependencies的内容,当前hutool-bom内的dependencies全部设置了version,就意味着在maven resolve的时候hutool-bom内就算存在dependencyManagement也不会产生任何作用。
1. 生成验证码,并返回
2. 校验验证码是否正确
1. 生成验证码
[URL]
GET /captcha/getCaptcha
[请求参数]
[响应]
{
"uuid": "fc2b40825f20470bb4f5d9868b33856f",
"img": "data:image/png;base64,issaxxxxxxxxgg=="
}
uuid 是为了方便在真实项目使用中做区分
2. 校验验证码是否正确
[URL]
POST /captcha/check
[请求参数]
{"uuid":"43b4b30bf1134e9f8430507b7babd620","code":""}
[响应]
{
true
}
根据用户输入的验证码,校验验证码是否正确,校验成功,返回true;校验失败,返回false
@Slf4j
@RestController
@RequestMapping("/captcha")
@AllArgsConstructor
public class CaptchaController {
private final SysCaptchaService sysCaptchaService;
/**
* 生成验证码
*/
@GetMapping("/getCaptcha")
public CaptchaResult getCaptcha(HttpSession session) {
return sysCaptchaService.getCaptcha(session);
}
/**
* 验证码校验
*
* @param param 验证码参数
*/
@PostMapping("/check")
public boolean checkCaptcha(@RequestBody CaptchaValidateParam param, HttpSession session) {
String uuid = param.getUuid();
String captcha = param.getCode();
if (StrUtil.isEmpty(uuid) || StrUtil.isEmpty(captcha)) {
log.error("验证码参数不能为空");
return false;
}
log.info("接收到验证码: uuId:{}, 验证码:{}", uuid, captcha);
// 参数校验
return sysCaptchaService.validate(uuid, captcha, session);
}
}
由于当用户输入验证码时,我们需要进行校验,因此,我们需要对生成的验证码进行存储,同时,需要存储验证码的生成时间,以便判断验证码是否超时
public class Constants {
public static final String CAPTCHA_CODE = "code";
public static final String CAPTCHA_UUID = "uuid";
}
public interface SysCaptchaService {
/**
* 获取验证码
*
* @param session
* @return
*/
CaptchaResult getCaptcha(HttpSession session);
/**
* 验证码效验
*
* @param uuid
* @param code
* @param session
* @return
*/
boolean validate(String uuid, String code, HttpSession session);
}
@Service
@RequiredArgsConstructor
@Slf4j
public class SysCaptchaServiceImpl implements SysCaptchaService {
private final CaptchaProperties captchaProperties;
private final CodeGenerator codeGenerator;
private final Font captchaFont;
@Override
public CaptchaResult getCaptcha(HttpSession session) {
String captchaType = captchaProperties.getType();
int width = captchaProperties.getWidth();
int height = captchaProperties.getHeight();
int interfereCount = captchaProperties.getInterfereCount();
int codeLength = captchaProperties.getCode().getLength();
AbstractCaptcha captcha;
if (CaptchaTypeEnums.CIRCLE.name().equalsIgnoreCase(captchaType)) {
captcha = CaptchaUtil.createCircleCaptcha(width, height, codeLength, interfereCount);
} else if (CaptchaTypeEnums.GIF.name().equalsIgnoreCase(captchaType)) {
captcha = CaptchaUtil.createGifCaptcha(width, height, codeLength);
} else if (CaptchaTypeEnums.LINE.name().equalsIgnoreCase(captchaType)) {
captcha = CaptchaUtil.createLineCaptcha(width, height, codeLength, interfereCount);
} else if (CaptchaTypeEnums.SHEAR.name().equalsIgnoreCase(captchaType)) {
captcha = CaptchaUtil.createShearCaptcha(width, height, codeLength, interfereCount);
} else {
throw new IllegalArgumentException("Invalid captcha type: " + captchaType);
}
captcha.setGenerator(codeGenerator);
captcha.setTextAlpha(captchaProperties.getTextAlpha());
captcha.setFont(captchaFont);
String code = captcha.getCode();
String imageBase64Data = captcha.getImageBase64Data();
// 验证码文本缓存至Redis,用于登录校验
String uuid = IdUtil.fastSimpleUUID();
session.setAttribute(Constants.CAPTCHA_CODE, code);
session.setAttribute(Constants.CAPTCHA_UUID, uuid);
return CaptchaResult.builder().img(imageBase64Data).uuid(uuid).build();
}
@Override
public boolean validate(String uuid, String code, HttpSession session) {
// session中获取验证码
String captchaCode = (String) session.getAttribute(Constants.CAPTCHA_CODE);
return codeGenerator.verify(captchaCode, code);
}
将用户输入的验证码与存储在 session 中的验证码进行对比,判断其是否相同,若相同且在1min内,则验证成功
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
#inputCaptcha {
height: 30px;
vertical-align: middle;
}
#verificationCodeImg {
vertical-align: middle;
}
#checkCaptcha {
height: 40px;
width: 100px;
border: 1px solid #000;
border-radius: 5px;
margin-left: 10px;
vertical-align: middle;
}
</style>
</head>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<body>
<div id="app">
<h1>{{ message }}</h1>
<input type="text" v-model="inputCaptcha" id="inputCaptcha">
<img id="verificationCodeImg" :src="captchaData.img" alt="验证码" @click="refreshCaptcha" title="看不清?换一张"/>
<input type="button" value="提交" id="checkCaptcha" @click="checkCaptcha">
</div>
<script type="module">
import {createApp, ref, onMounted} from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
createApp({
setup() {
const message = ref('验证码校验')
const inputCaptcha = ref('')
const captchaData = ref({
img: '',
uuid: ''
})
const refreshCaptcha = () => {
$.ajax({
url: '/captcha/getCaptcha',
type: 'GET',
success: function (data) {
captchaData.value = data
}
})
}
const checkCaptcha = () => {
const dataFrom = {
uuid: captchaData.value.uuid,
code: inputCaptcha.value
}
$.ajax({
url: '/captcha/check',
type: 'POST',
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify(dataFrom),
success: function (data) {
if (data) {
alert('验证码正确')
refreshCaptcha()
} else {
alert('验证码错误')
refreshCaptcha()
}
}
})
}
// 页面加载完成后,刷新验证码
onMounted(() => {
refreshCaptcha()
})
return {
message,
captchaData,
inputCaptcha,
refreshCaptcha,
checkCaptcha
}
}
}).mount('#app')
</script>
</body>
</html>
验证成功:
验证失败:
为让验证码有多样性,这里将验证的生成放入了application.yml
配置文件中,内容如下:
# 验证码配置
captcha:
# 验证码类型 circle-圆圈干扰验证码|gif-Gif验证码|line-干扰线验证码|shear-扭曲干扰验证码
type: circle
# 验证码宽度
width: 130
# 验证码高度
height: 48
# 验证码干扰元素个数
interfere-count: 2
# 文本透明度(0.0-1.0)
text-alpha: 0.8
# 验证码字符配置
code:
# 验证码字符类型 math-算术|random-随机字符
type: math
# 验证码字符长度,type=算术时,表示运算位数(1:个位数运算 2:十位数运算);type=随机字符时,表示字符个数
length: 1
# 验证码字体
font:
# 字体名称 Dialog|DialogInput|Monospaced|Serif|SansSerif
name: SansSerif
# 字体样式 0-普通|1-粗体|2-斜体
weight: 1
# 字体大小
size: 20
# 验证码有效期(秒)
expire-seconds: 120
项目代码示例地址:https://gitcode.com/qq_35098526/article_code/tree/main/hutool-captcha-demo
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。