基于SpringBoot和Hutool工具包實(shí)現(xiàn)驗(yàn)證碼的案例
驗(yàn)證碼案例
隨著安全性的要求越來(lái)越高,目前項(xiàng)目中很多都會(huì)使用驗(yàn)證碼,只要涉及到登錄,絕大多數(shù)都會(huì)有驗(yàn)證的要求,驗(yàn)證碼的形式也是多種多樣,更復(fù)雜的圖形驗(yàn)證碼和行為驗(yàn)證碼已經(jīng)成為了更流行的趨勢(shì)。

驗(yàn)證碼的實(shí)現(xiàn)方式很多,可以前端實(shí)現(xiàn),也可以后端實(shí)現(xiàn)。網(wǎng)上也有比較多的插件或者工具包可以使用,這里選擇使用 Hutool工具包 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的驗(yàn)證碼案例。完整代碼見(jiàn)文章末尾。
1. 需求
最終實(shí)現(xiàn)的驗(yàn)證碼界面如下圖所示:
1. 頁(yè)面生成驗(yàn)證碼
2. 輸入驗(yàn)證碼,點(diǎn)擊提交,驗(yàn)證用戶輸入驗(yàn)證碼是否正確且是否超時(shí),正確且未超時(shí)則進(jìn)行頁(yè)面跳轉(zhuǎn),錯(cuò)誤或已超時(shí)則進(jìn)行提示,并更換驗(yàn)證碼

2. 準(zhǔn)備工作
創(chuàng)建SpringBoot項(xiàng)目,引入Spring-Web-MVC和Lombok的依賴包,前端界面會(huì)在后面提供.

3. 約定前后端交互接口
需求分析
后端需要提供兩個(gè)服務(wù):
- 生成驗(yàn)證碼,并返回驗(yàn)證碼.
- 校驗(yàn)驗(yàn)證碼是否正確.
接口定義
1)生成驗(yàn)證碼
請(qǐng)求:
請(qǐng)求URL:/captcha/get
響應(yīng):瀏覽器顯示圖片內(nèi)容
瀏覽器給服務(wù)器發(fā)送一個(gè) /captcha/get 請(qǐng)求,服務(wù)器返回一個(gè)圖片,瀏覽器顯示在頁(yè)面上
2)校驗(yàn)驗(yàn)證碼是否正確
請(qǐng)求:
請(qǐng)求URL:/captcha/check 請(qǐng)求參數(shù):captcha=驗(yàn)證碼字符串
響應(yīng):
true or false 根據(jù)用戶輸入的驗(yàn)證碼,校驗(yàn)驗(yàn)證碼是否正確,并判斷驗(yàn)證碼是否超時(shí)
4. Hutool 工具介紹
Hutool官網(wǎng):https://hutool.cn/
Hutool參考文檔:https://hutool.cn/docs/#/

要使用Hutool工具包,需要在pom.xml文件中添加對(duì)應(yīng)的依賴,參考文檔中有詳細(xì)介紹:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>在Hutolol參考文檔中找到圖形驗(yàn)證碼部分:

接下來(lái)可以就可以參考Hutool工具提供的方法,快速生成驗(yàn)證碼,里面的介紹非常清晰,很容易看懂。此處使用如下格式驗(yàn)證碼:

5. 實(shí)現(xiàn)驗(yàn)證碼
項(xiàng)目目錄結(jié)構(gòu)如下:

后端代碼
實(shí)現(xiàn)接口
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 {
@Autowired
private CaptchaProperties captchaProp;
@RequestMapping("/get")
public void getCaptcha(HttpServletResponse response, HttpSession session) {
//定義圖形驗(yàn)證碼的長(zhǎng)和寬(配置默認(rèn)值)
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProp.getWidth(), captchaProp.getHeight());
//細(xì)節(jié)問(wèn)題,不影響程序
//設(shè)置返回類型
response.setContentType("image/jpeg");
//靜止緩存
response.setHeader("Progma", "No-cache");
try {
//圖形驗(yàn)證碼寫(xiě)出,可以寫(xiě)出到文件,也可以寫(xiě)出到流
lineCaptcha.write(response.getOutputStream());
//同時(shí)將驗(yàn)證碼內(nèi)容和當(dāng)前時(shí)間戳存儲(chǔ)到Session中
//此處Session的鍵可以配置成常量
session.setAttribute(captchaProp.getSession().getKey(), lineCaptcha.getCode());
session.setAttribute(captchaProp.getSession().getDate(), new Date());
//關(guān)流
response.getOutputStream().close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//驗(yàn)證碼生效時(shí)間限制
private static final long VALID_MILLIS_TIME = 60 * 1000;
@RequestMapping("/check")
public boolean checkCaptcha(String captcha, HttpSession session) {
//保證傳過(guò)來(lái)的參數(shù)是合法的
if (StringUtils.hasLength(captcha)) {
//根據(jù)配置的默認(rèn)session信息獲取key和date
String key = (String) session.getAttribute(captchaProp.getSession().getKey());
Date date = (Date) session.getAttribute(captchaProp.getSession().getDate());
//1.驗(yàn)證碼正確(不區(qū)分大小寫(xiě)) 2.驗(yàn)證碼還未失效
return key.equalsIgnoreCase(captcha)
&& System.currentTimeMillis() - date.getTime() < VALID_MILLIS_TIME;
}
return false;
}
}代碼解析:
通過(guò)@Autowired注解注入了一個(gè)CaptchaProperties對(duì)象,這個(gè)對(duì)象是用來(lái)配置圖形驗(yàn)證碼的屬性的。使用這種方式是因?yàn)榇a中的有些屬性可能會(huì)在別處使用,且它們都是固定的,例如圖形驗(yàn)證碼的長(zhǎng)和寬,Session的字段名等。將這些屬性封裝在一個(gè)對(duì)象中,并通過(guò)讀取配置文件的方式綁定屬性值。
在@RequestMapping注解的getCaptcha方法中,使用Hutool包的CaptchaUtil.createLineCaptcha方法創(chuàng)建了一個(gè)圖形驗(yàn)證碼對(duì)象lineCaptcha,其大小由配置文件中的captchaProp.getWidth()和captchaProp.getHeight()決定。然后,將驗(yàn)證碼內(nèi)容和當(dāng)前時(shí)間戳存儲(chǔ)到HttpSession中,以便后續(xù)校驗(yàn)驗(yàn)證碼的時(shí)候使用。最后,將圖形驗(yàn)證碼寫(xiě)出到HttpServletResponse的輸出流中,以返回給前端頁(yè)面顯示。
在@RequestMapping注解的checkCaptcha方法中,首先判斷傳入的驗(yàn)證碼參數(shù)是否合法。如果合法,則從HttpSession中獲取存儲(chǔ)的驗(yàn)證碼內(nèi)容和時(shí)間戳信息,并進(jìn)行比較。如果驗(yàn)證碼正確且未過(guò)期,則返回true,否則返回false。
CaptchaProperties類的實(shí)現(xiàn)和配置文件(.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類
@Data
public static class Session {
private String key;
private String date;
}
}spring:
application:
name:
captcha-demo
captcha:
width: 200
height: 100
session:
key: CAPTCHA_SESSION_KEY
date: CAPTCHA_SESSION_DATE
此處還沒(méi)有前端代碼,但是已經(jīng)可以先測(cè)試了,通常寫(xiě)好一個(gè)接口就可以測(cè)試一下。
啟動(dòng)項(xiàng)目,再訪問(wèn) http://127.0.0.1:8080/captcha/get 顯示驗(yàn)證碼圖片如下:

通過(guò) Fiddler 進(jìn)行抓包,HTTP請(qǐng)求和響應(yīng)數(shù)據(jù)如下,圖片就在響應(yīng)的body部分:

前端代碼
注意前端代碼要放在resources的static目錄下
index.html(重點(diǎn)關(guān)注script標(biāo)簽內(nèi)的代碼):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>驗(yàn)證碼</title>
<style>
#inputCaptcha {
height: 30px;
vertical-align: middle;
}
#verificationCodeImg {
vertical-align: middle;
}
#checkCaptcha {
height: 40px;
width: 100px;
}
</style>
</head>
<body>
<h1>輸入驗(yàn)證碼</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>
//點(diǎn)擊圖片,切換驗(yàn)證碼
$("#verificationCodeImg").click(function () {
//$(this).hide().attr('src', '/captcha/get?dt=' + new Date().getTime()).fadeIn();
//使用attr()方法修改src屬性值,獲取一個(gè)新的驗(yàn)證碼圖片,后面添加一個(gè)時(shí)間戳參數(shù)來(lái)保證每次請(qǐng)求的驗(yàn)證碼圖片都是不同的
$(this).attr('src', '/captcha/get?dt=' + new Date().getTime());
});
//點(diǎn)擊提交按鈕,進(jìn)行驗(yàn)證碼校驗(yàn)
$("#checkCaptcha").click(function () {
$.ajax({
url: "/captcha/check",
type: "post",
data: {
captcha: $("#inputCaptcha").val()
},
success: function (result) {
if (result) {
location.href = "success.html";
} else {
alert("驗(yàn)證碼錯(cuò)誤或已超時(shí)");
//驗(yàn)證碼錯(cuò)誤,重新生成驗(yàn)證碼
$("#verificationCodeImg").attr('src', '/captcha/get?dt=' + new Date().getTime());
$("#inputCaptcha").val("");
}
}
});
});
</script>
</body>
</html>JavaScript代碼中主要包含兩部分邏輯:
點(diǎn)擊圖片,切換驗(yàn)證碼: 當(dāng)id為"verificationCodeImg"的圖片被點(diǎn)擊時(shí),會(huì)觸發(fā)click事件的回調(diào)函數(shù)?;卣{(diào)函數(shù)通過(guò)修改圖片的src屬性,向后端發(fā)送一個(gè)請(qǐng)求來(lái)獲取新的驗(yàn)證碼圖片,并使用當(dāng)前時(shí)間戳作為參數(shù),以確保每次請(qǐng)求的驗(yàn)證碼圖片都是不同的。最后,將獲取到的新圖片顯示出來(lái)。
點(diǎn)擊提交按鈕,進(jìn)行驗(yàn)證碼校驗(yàn): 當(dāng)id為"checkCaptcha"的按鈕被點(diǎn)擊時(shí),會(huì)觸發(fā)click事件的回調(diào)函數(shù)?;卣{(diào)函數(shù)通過(guò)使用jQuery的ajax方法發(fā)送一個(gè)POST請(qǐng)求到"/captcha/check"接口,并傳遞了一個(gè)名為"captcha"的參數(shù),該參數(shù)的值為id為"inputCaptcha"的輸入框中用戶輸入的驗(yàn)證碼。
在請(qǐng)求成功后的回調(diào)函數(shù)中,會(huì)根據(jù)后端返回的結(jié)果(result)進(jìn)行處理。如果校驗(yàn)成功,則跳轉(zhuǎn)到"success.html"頁(yè)面;如果校驗(yàn)失敗,則彈出一個(gè)提示框顯示"驗(yàn)證碼錯(cuò)誤或已超時(shí)",并重新生成新的驗(yàn)證碼圖片并清空輸入框中的驗(yàn)證碼。
success.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>驗(yàn)證成功頁(yè)</title>
</head>
<body>
<h1>驗(yàn)證成功</h1>
</body>
</html>6. 運(yùn)行測(cè)試
啟動(dòng)項(xiàng)目,瀏覽器訪問(wèn) http://127.0.0.1:8080/index.html 或 http://localhost:8080/index.html
輸入錯(cuò)誤的驗(yàn)證碼:

提示正確,且驗(yàn)證碼能正確刷新,超時(shí)同樣會(huì)提示以上錯(cuò)誤。且點(diǎn)擊驗(yàn)證碼圖片時(shí),會(huì)重新生成驗(yàn)證碼。

驗(yàn)證成功,頁(yè)面正確跳轉(zhuǎn),測(cè)試完成。
以上就是基于SpringBoot和Hutool工具包實(shí)現(xiàn)驗(yàn)證碼的案例的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Hutool驗(yàn)證碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java線程并發(fā)控制同步工具CountDownLatch
這篇文章主要為大家介紹了java線程并發(fā)控制同步工具CountDownLatch使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
sharding-jdbc實(shí)現(xiàn)分頁(yè)查詢的示例代碼
sharding-jdbc是一個(gè)輕量級(jí)Java框架,它提供了分布式數(shù)據(jù)庫(kù)中間件的功能,支持水平分表和分庫(kù)分表,在分頁(yè)查詢方面,sharding-jdbc支持兩種方式:基于物理分頁(yè)和基于邏輯分頁(yè),本文給大家介紹sharding-jdbc如何實(shí)現(xiàn)分頁(yè)查詢,需要的朋友可以參考下2024-05-05
java中Spring Security的實(shí)例詳解
這篇文章主要介紹了java中Spring Security的實(shí)例詳解的相關(guān)資料,spring security是一個(gè)多方面的安全認(rèn)證框架,提供了基于JavaEE規(guī)范的完整的安全認(rèn)證解決方案,需要的朋友可以參考下2017-09-09
基于Java實(shí)現(xiàn)馬踏棋盤(pán)游戲算法
這篇文章主要為大家詳細(xì)介紹了基于Java實(shí)現(xiàn)馬踏棋盤(pán)游戲算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
Java遞歸算法詳解(動(dòng)力節(jié)點(diǎn)整理)
Java遞歸算法是基于Java語(yǔ)言實(shí)現(xiàn)的遞歸算法。遞歸算法對(duì)解決一大類問(wèn)題很有效,它可以使算法簡(jiǎn)潔和易于理解。接下來(lái)通過(guò)本文給大家介紹Java遞歸算法相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧2017-03-03
基于 Cursor 開(kāi)發(fā) Spring Boot 項(xiàng)目詳細(xì)攻略
Cursor是集成GPT4、Claude3.5等LLM的VSCode類AI編程工具,支持SpringBoot項(xiàng)目開(kāi)發(fā)全流程,涵蓋環(huán)境配置、代碼生成、數(shù)據(jù)庫(kù)連接及部署,提供智能輔助、代碼優(yōu)化與錯(cuò)誤修復(fù)功能,助力高效開(kāi)發(fā),本文給大家介紹基于Cursor開(kāi)發(fā)Spring Boot項(xiàng)目詳細(xì)攻略,感興趣的朋友一起看看吧2025-09-09

