1、前言
kaptcha是一個非常實用的短信驗證碼生成工具,通過簡單配置即可實現多樣化的驗證碼。
2、引入依賴
<!--第三方驗證碼-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
3、前台
假設前台調用樣式如下:
<img alt="驗證碼" width="128" height="42" @click="changeImage" src="項目地址/validate/captcha-image" ref="checkCode"/>
通過調用 /validate/captcha-image 接口地址獲取驗證碼。
4、后台
4.1 controller
@RequestMapping("/captcha-image")
public void defaultKaptcha(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception{
validateService.defaultKaptcha(httpServletRequest,httpServletResponse);
}
4.2 serviceImpl
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
DefaultKaptcha defaultKaptcha;
/*驗證碼失效時間 15分鍾*/
private static final int VALID_CODE_CACHE_EXPIRE_TIME = 900;
/**
* 生成圖片驗證碼
* @param httpServletRequest request
* @param httpServletResponse response
*/
public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)throws Exception{
byte[] captchaChallengeAsJpeg = null;
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
/*生產驗證碼字符串並保存到session中*/
String createText = defaultKaptcha.createText();
String key = String.format("login_valid_code_%s", httpServletRequest.getSession().getId());
redisTemplate.opsForValue().set(key, createText, VALID_CODE_CACHE_EXPIRE_TIME, TimeUnit.SECONDS);
/*httpServletRequest.getSession().setAttribute("vrifyCode", createText);*/
/*使用生產的驗證碼字符串返回一個BufferedImage對象並轉為byte寫入到byte數組中*/
BufferedImage challenge = defaultKaptcha.createImage(createText);
ImageIO.write(challenge, "jpg", jpegOutputStream);
} catch (IllegalArgumentException e) {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
/*定義response輸出類型為image/jpeg類型,使用response輸出流輸出圖片的byte數組*/
captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
httpServletResponse.setHeader("Cache-Control", "no-store");
httpServletResponse.setHeader("Pragma", "no-cache");
httpServletResponse.setDateHeader("Expires", 0);
httpServletResponse.setContentType("image/jpeg");
ServletOutputStream responseOutputStream =
httpServletResponse.getOutputStream();
responseOutputStream.write(captchaChallengeAsJpeg);
responseOutputStream.flush();
responseOutputStream.close();
}
補充:DefaultKaptcha是引入kaptcha依賴后即直接可引入的;
如上思路代碼已經很清晰了,通過DefaultKaptcha創建驗證碼文本,然后存入redis一份,用於后面的驗證使用;
注意:redis 拼接的 key 規則為 login_valid_code_ + sessionId(session id)
5、效果
前端實際應用效果:

瀏覽器直接調用接口效果:

6、驗證
6.1 controller
從redis中取
/**
* 驗證驗證碼
* @return Object
*/
@UnAuthorization
@RequestMapping(value = "code/check", method = {RequestMethod.POST})
public Object checkCode(@RequestBody @Valid CheckValidateRequest checkValidateRequest , BindingResult bindingResult, HttpServletRequest request) {
return validateService.checkValidateCode(httpServletRequest.getSession().getId(),checkValidateRequest.getValidCode());
}
6.2 serviceImpl
/**
* 驗證短信驗證碼有效性
* @param mobile 手機號碼 或者 sessionId
* @param validCode 驗證碼
* @return boolean
*/
public boolean checkValidateCode(String sessionId, String validCode) {
Object iValidCodeFromRedis = cacheService.getCache(String.format("login_valid_code_%s", sessionId));
String sValidCodeFromRedis = String.valueOf(iValidCodeFromRedis);
if (StringUtils.isNotBlank(sValidCodeFromRedis) && validCode.equalsIgnoreCase(sValidCodeFromRedis)) {
return true;
}
throw new CommonException(ValidateStatusEn.CHECK_VALID_CODE_FAILED.getErrorMsg(), ValidateStatusEn.CHECK_VALID_CODE_FAILED.getErrorCode());
}
補充:通過 login_valid_code_ + sessionId 從 redis 中獲取驗證碼進行校驗。
我創建了一個用來記錄自己學習之路的公眾號,感興趣的小伙伴可以關注一下微信公眾號:niceyoo
