一、使用的依賴(lài)
此處需要引入的依賴(lài)hutool-captcha:
<!-- 獲取圖形驗(yàn)證碼 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>5.8.18</version>
</dependency>
注:hutool-captcha已經(jīng)包含在了 hutool-all 中,也可以直接引入 hutool-all。
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.11</version> </dependency>
二、使用依賴(lài)
生成驗(yàn)證碼的工具是 CaptchaUtil,基本使用方式如下:
/**
* 獲取驗(yàn)證碼
*/
@Test
public void getCaptcha() throws FileNotFoundException {
//生成帶有直線(xiàn)干擾的驗(yàn)證碼圖片
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(300, 100, 4, 20);//指定(寬,高,驗(yàn)證碼數(shù)量,干擾項(xiàng)數(shù)量)
//獲取驗(yàn)證碼的信息
System.out.println(lineCaptcha.getCode());//驗(yàn)證碼的文本信息,用于校對(duì)
//將驗(yàn)證碼圖片轉(zhuǎn)換為base64格式字符串
System.out.println("不帶數(shù)據(jù)格式前綴:" + lineCaptcha.getImageBase64());//不帶數(shù)據(jù)格式前綴
System.out.println("帶數(shù)據(jù)格式前綴:" + lineCaptcha.getImageBase64Data());//帶數(shù)據(jù)格式前綴
//保存驗(yàn)證碼圖片
lineCaptcha.write("D:\\@Information\\ceshia\\1.png");//1傳保存路徑
lineCaptcha.write(new File("D:\\@Information\\ceshia\\2.png"));//2傳文件
lineCaptcha.write(new FileOutputStream(new File("D:\\@Information\\ceshia\\3.png")));//3傳輸出流
boolean b = lineCaptcha.verify("1wcc");//校驗(yàn)用戶(hù)輸入的驗(yàn)證碼, b為true表示驗(yàn)證碼正確
}

關(guān)于base64圖片:base64可以將圖片轉(zhuǎn)為字符串,將驗(yàn)證碼圖片以base64格式發(fā)送??梢詼p少http請(qǐng)求次數(shù),同時(shí)將圖片和對(duì)應(yīng)的key發(fā)送到前端頁(yè)面,而服務(wù)器上只需要保存驗(yàn)證碼的值和key用來(lái)驗(yàn)證即可。
在上例中
lineCaptcha.getImageBase64()獲取的是不帶前綴的base64格式圖片,發(fā)送頁(yè)面上去后需要手動(dòng)拼接數(shù)據(jù)格式前綴才能正常識(shí)別圖片。而lineCaptcha.getImageBase64Data()獲取的是已經(jīng)帶上數(shù)據(jù)前綴的字符串,不許要進(jìn)行額外的處理。
CaptchaUtil驗(yàn)證碼生成工具不只是有createLineCaptcha一個(gè)方法,還有createCircleCaptcha、createShearCaptcha和createGifCaptcha等不同的方法。
它們的區(qū)別就是驗(yàn)證碼的干擾項(xiàng)不一樣。具體使用和區(qū)別可以簡(jiǎn)單瀏覽下:
/**
* 獲取驗(yàn)證碼`createCircleCaptcha`
*/
@Test
public void getCaptcha() throws FileNotFoundException {
//生成隨機(jī)圓圈干擾驗(yàn)證碼圖片
CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(300, 100, 4, 20);//指定(寬,高,驗(yàn)證碼數(shù)量,干擾項(xiàng)數(shù)量)
//獲取驗(yàn)證碼的信息
System.out.println(circleCaptcha.getCode());//驗(yàn)證碼的文本信息,用于校對(duì)
//將驗(yàn)證碼圖片轉(zhuǎn)換為base64格式字符串
System.out.println("不帶數(shù)據(jù)格式前綴:" + circleCaptcha.getImageBase64());//不帶數(shù)據(jù)格式前綴
System.out.println("帶數(shù)據(jù)格式前綴:" + circleCaptcha.getImageBase64Data());//帶數(shù)據(jù)格式前綴
//保存驗(yàn)證碼圖片
circleCaptcha.write("D:\\@Information\\ceshia\\1.png");//傳保存路徑
circleCaptcha.write(new File("D:\\@Information\\ceshia\\2.png"));//傳文件
circleCaptcha.write(new FileOutputStream(new File("D:\\@Information\\ceshia\\3.png")));//傳輸出流
boolean b = lineCaptcha.verify("g2zf");//校驗(yàn)用戶(hù)輸入的驗(yàn)證碼, b為true表示驗(yàn)證碼正確
}

/**
* 獲取驗(yàn)證碼`createShearCaptcha`
*/
@Test
public void getCaptcha() throws FileNotFoundException {
//生成斜線(xiàn)遮擋的驗(yàn)證碼圖片
ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(300, 100, 4, 1);//指定(寬,高,驗(yàn)證碼數(shù)量,干擾項(xiàng)斜線(xiàn)的寬度)
//獲取驗(yàn)證碼的信息
System.out.println(shearCaptcha.getCode());//驗(yàn)證碼的文本信息,用于校對(duì)
//將驗(yàn)證碼圖片轉(zhuǎn)換為base64格式字符串
System.out.println("不帶數(shù)據(jù)格式前綴:" + shearCaptcha.getImageBase64());//不帶數(shù)據(jù)格式前綴
System.out.println("帶數(shù)據(jù)格式前綴:" + shearCaptcha.getImageBase64Data());//帶數(shù)據(jù)格式前綴
//保存驗(yàn)證碼圖片
shearCaptcha.write("D:\\@Information\\ceshia\\1.png");//傳保存路徑
shearCaptcha.write(new File("D:\\@Information\\ceshia\\2.png"));//傳文件
shearCaptcha.write(new FileOutputStream(new File("D:\\@Information\\ceshia\\3.png")));//傳輸出流
boolean b = lineCaptcha.verify("zyhv");//校驗(yàn)用戶(hù)輸入的驗(yàn)證碼, b為true表示驗(yàn)證碼正確
}

/**
* 獲取驗(yàn)證碼`createGifCaptcha` 注意,這里生成的圖片后綴要是動(dòng)圖.gif的格式
*/
@Test
public void getCaptcha() throws FileNotFoundException {
//生成動(dòng)圖驗(yàn)證碼圖片
GifCaptcha gifCaptcha = CaptchaUtil.createGifCaptcha(300, 100, 4);//指定(寬,高,驗(yàn)證碼數(shù)量)
//獲取驗(yàn)證碼的信息
System.out.println(gifCaptcha.getCode());//驗(yàn)證碼的文本信息,用于校對(duì)
//將驗(yàn)證碼圖片轉(zhuǎn)換為base64格式字符串
System.out.println("不帶數(shù)據(jù)格式前綴:" + gifCaptcha.getImageBase64());//不帶數(shù)據(jù)格式前綴
System.out.println("帶數(shù)據(jù)格式前綴:" + gifCaptcha.getImageBase64Data());//帶數(shù)據(jù)格式前綴
//保存驗(yàn)證碼圖片
gifCaptcha.write("D:\\@Information\\ceshia\\1.gif");//傳保存路徑
gifCaptcha.write(new File("D:\\@Information\\ceshia\\2.gif"));//傳文件
gifCaptcha.write(new FileOutputStream(new File("D:\\@Information\\ceshia\\3.gif")));//傳輸出流
boolean b = lineCaptcha.verify("zjsx");//校驗(yàn)用戶(hù)輸入的驗(yàn)證碼, b為true表示驗(yàn)證碼正確
}

三、項(xiàng)目中的使用
在前后端分離的場(chǎng)景中,后端向前端發(fā)送驗(yàn)證碼。(涉及到使用redis存儲(chǔ)驗(yàn)證碼,和lombok相關(guān),不知道的可以先不看啦)
創(chuàng)建:下面使用的是CaptchaUtil.createGifCaptcha方法創(chuàng)建的動(dòng)圖驗(yàn)證碼,通過(guò)uuid生成驗(yàn)證碼的key。在通過(guò)redis緩存驗(yàn)證碼的key、value后,將圖片轉(zhuǎn)成base64字符串和key一起發(fā)送出去。
驗(yàn)證:驗(yàn)證沒(méi)有使用自帶的lineCaptcha.verify()方法,而是通過(guò)redis手動(dòng)獲取信息檢查驗(yàn)證。如果redis取出驗(yàn)證碼信息的時(shí)候出現(xiàn)異常,即為驗(yàn)證失敗。
/**
* 獲取驗(yàn)證碼信息
*
* @return CaptchaVO對(duì)象,包含一個(gè)隨機(jī)驗(yàn)證碼圖片及其對(duì)應(yīng)的key
*/
public CaptchaVO getGifCaptcha() {
//生成驗(yàn)證碼圖片, 定義圖形驗(yàn)證碼的長(zhǎng)、寬、驗(yàn)證碼字符數(shù)(這里采用的是動(dòng)圖驗(yàn)證碼)
GifCaptcha captcha = CaptchaUtil.createGifCaptcha(300, 100, 4);
//生成驗(yàn)證碼唯一標(biāo)識(shí),這里主要是為了臨時(shí)的區(qū)分用戶(hù)端的,驗(yàn)證碼唯一標(biāo)識(shí)這里采用的是uuid生成
String captchaKey = UUID.randomUUID().toString().replace("-","");
//獲得圖片,base64格式
String image = captcha.getImageBase64();
//獲取驗(yàn)證碼圖片上的字母,即驗(yàn)證碼的答案
String captchaValue = captcha.getCode();
//將驗(yàn)證碼信息存入redis
redisTemplate.opsForValue().set(
captchaKey, captchaValue, //設(shè)置數(shù)據(jù)
120, TimeUnit.SECONDS); //設(shè)置有效時(shí)間
//封裝對(duì)象,返回?cái)?shù)據(jù)
return CaptchaVO.builder()
.msgCodeUrl(image) //驗(yàn)證碼圖片
.keyCode(captchaKey) //驗(yàn)證碼圖片對(duì)應(yīng)key
.build();
}
/**
* 檢查驗(yàn)證碼的正確性
*
* @param captchaKey 當(dāng)前用戶(hù)的驗(yàn)證碼的key
* @param UserCaptchaValue 用戶(hù)填寫(xiě)的驗(yàn)證碼信息
*/
public void checkMsgCode(String captchaKey, String UserCaptchaValue) {
if (captchaKey != null && UserCaptchaValue != null) { //非空判斷
try {
String trueCaptchaValue =(String)redisTemplate.opsForValue().get(captchaKey);//根據(jù)key獲取真正的驗(yàn)證碼信息
redisTemplate.delete(captchaKey);//刪除驗(yàn)證碼信息,此條驗(yàn)證碼作廢
if (trueCaptchaValue != null && UserCaptchaValue.compareToIgnoreCase(trueCaptchaValue) == 0) {
//驗(yàn)證碼正確,退出
return;
}
} catch (Exception ignored) {
//忽略異常,
}
}
throw new RuntimeException("驗(yàn)證碼錯(cuò)誤或已過(guò)期");//驗(yàn)證碼不正確,拋出異常
}