com.gitee.cliveyuan.tools.web.CaptchaTools Maven / Gradle / Ivy
Show all versions of java-tools Show documentation
package com.gitee.cliveyuan.tools.web;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gitee.cliveyuan.tools.Assert;
import com.gitee.cliveyuan.tools.IdTools;
import com.gitee.cliveyuan.tools.StringTools;
import com.gitee.cliveyuan.tools.VerifyCodeTools;
import com.gitee.cliveyuan.tools.bean.Captcha;
import com.gitee.cliveyuan.tools.bean.CaptchaCodeResult;
import com.gitee.cliveyuan.tools.bean.CaptchaRequest;
import com.gitee.cliveyuan.tools.bean.CaptchaV2;
import com.gitee.cliveyuan.tools.bean.CaptchaValidate;
import com.gitee.cliveyuan.tools.enums.CaptchaGenerateType;
import com.gitee.cliveyuan.tools.enums.CaptchaType;
import com.gitee.cliveyuan.tools.exception.CaptchaException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Objects;
/**
* 验证码工具类
*
* @author clive
* Created on 2018-07-27
*/
public class CaptchaTools {
private final static Logger logger = LoggerFactory.getLogger(CaptchaTools.class);
public final static String DEFAULT_CAPTCHA_NAME = "CAPTCHA_NAME";
public final static int DEFAULT_CAPTCHA_LENGTH = 5;
public final static int DEFAULT_CAPTCHA_WIDTH = 300;
public final static int DEFAULT_CAPTCHA_HEIGHT = 100;
private CaptchaTools() {
}
/**
* 验证验证码
* 验证码正确不抛异常, 错误抛CaptchaException异常
*
* @param inputCaptcha 输入的验证码
* @param request 请求
* @deprecated CaptchaTools#validate(CaptchaValidate captchaValidate)
*/
@Deprecated
public static void validate(Captcha inputCaptcha, HttpServletRequest request) {
validate(inputCaptcha, request, DEFAULT_CAPTCHA_NAME);
}
/**
* 验证验证码
* 验证码正确不抛异常, 错误抛CaptchaException异常
*
* @param inputCaptcha 输入的验证码
* @param request 请求
* @param captchaName 验证码session名
* @see CaptchaTools#validate(CaptchaValidate captchaValidate)
* @deprecated CaptchaTools#validate(CaptchaValidate captchaValidate)
*/
@Deprecated
public static void validate(Captcha inputCaptcha, HttpServletRequest request, String captchaName) {
logger.debug("CaptchaTools.validate: inputCaptcha={}, captchaName={}", inputCaptcha, captchaName);
Assert.notNull(request, "request is required");
HttpSession session = request.getSession();
if (Objects.isNull(inputCaptcha)) throw CaptchaException.captchaIsNull();
if (StringTools.isBlank(inputCaptcha.getCaptchaId())) throw CaptchaException.idIsEmpty();
if (StringTools.isBlank(inputCaptcha.getCaptchaValue())) throw CaptchaException.valueIsEmpty();
if (StringTools.isBlank(captchaName)) captchaName = DEFAULT_CAPTCHA_NAME;
inputCaptcha.setCaptchaValue(inputCaptcha.getCaptchaValue().toLowerCase());
String captchaStr = (String) session.getAttribute(captchaName);
if (StringTools.isBlank(captchaStr)) throw CaptchaException.notInSession();
Captcha captcha = JSONObject.parseObject(captchaStr, Captcha.class);
if (Objects.isNull(captcha)) throw CaptchaException.parseJsonError();
logger.debug("CaptchaTools.validate: 输入的验证码: {}, 生成的验证码: {}", inputCaptcha, captcha);
if (!Objects.equals(inputCaptcha, captcha)) throw CaptchaException.notMatch();
logger.debug("CaptchaTools.validate: matched");
}
/**
* 校验验证码 v2
*
* 验证码正确不抛异常, 错误抛CaptchaException异常
*
* @param captchaValidate
*/
public static boolean validate(CaptchaValidate captchaValidate) {
logger.debug("CaptchaTools.validate: captchaValidate={}", captchaValidate);
try {
Assert.notNull(captchaValidate, "captchaValidate is null");
HttpServletRequest request = captchaValidate.getRequest();
CacheManager cacheManager = captchaValidate.getCacheManager();
String cacheNamespace = captchaValidate.getCacheNamespace();
Assert.notNull(captchaValidate.getGenerateType(), "generateType is null");
if (CaptchaGenerateType.SESSION.equals(captchaValidate.getGenerateType())) {
Assert.notNull(request, "request is null");
} else if (CaptchaGenerateType.CACHE.equals(captchaValidate.getGenerateType())) {
Assert.notNull(cacheManager, "cacheManager is null");
Assert.notNull(cacheNamespace, "cacheNamespace is null");
}
CaptchaV2 inputCaptcha = captchaValidate.getCaptcha();
String captchaName = captchaValidate.getName();
if (Objects.isNull(inputCaptcha))
throw CaptchaException.captchaIsNull();
if (StringTools.isBlank(inputCaptcha.getId()))
throw CaptchaException.idIsEmpty();
if (StringTools.isBlank(inputCaptcha.getValue()))
throw CaptchaException.valueIsEmpty();
if (StringTools.isBlank(captchaName))
captchaName = DEFAULT_CAPTCHA_NAME;
inputCaptcha.setValue(inputCaptcha.getValue().toLowerCase());
CaptchaV2 captcha = null;
if (CaptchaGenerateType.SESSION.equals(captchaValidate.getGenerateType())) {
captcha = getFromSession(captchaValidate, captchaName);
} else if (CaptchaGenerateType.CACHE.equals(captchaValidate.getGenerateType())) {
captcha = getFromCache(captchaValidate, captchaName);
}
if (Objects.isNull(captcha))
throw CaptchaException.parseJsonError();
logger.debug("CaptchaTools.validate: 输入的验证码: {}, 生成的验证码: {}", inputCaptcha, captcha);
// 移除验证码
removeCaptcha(captchaValidate, captchaName);
captcha.setValue(captcha.getValue().toLowerCase()); // fix 大小写不匹配问题
if (!Objects.equals(inputCaptcha, captcha)) {
throw CaptchaException.notMatch();
}
} catch (CaptchaException e) {
if (captchaValidate.isThrowExceptionWhenError()) {
throw e;
}
logger.info("CaptchaTools.validate: ERROR code={}, msg={}", e.getCode(), e.getMessage());
return false;
}
logger.debug("CaptchaTools.validate: matched");
return true;
}
/**
* 生成验证码
*
* @param request 请求
* @param response 响应
* @param id 验证码id 初始生成时可不传
*/
@Deprecated
public static void generate(
HttpServletRequest request,
HttpServletResponse response,
String id
) {
generate(request, response, id, DEFAULT_CAPTCHA_NAME);
}
/**
* 生成验证码
*
* @param request 请求
* @param response 响应
* @param id 验证码id 初始生成时可不传
* @param captchaName 验证码session名
*/
@Deprecated
public static void generate(
HttpServletRequest request,
HttpServletResponse response,
String id,
String captchaName
) {
generate(request, response, id, captchaName, DEFAULT_CAPTCHA_LENGTH);
}
/**
* 生成验证码
*
* @param request 请求
* @param response 响应
* @param id 验证码id 初始生成时可不传
* @param captchaName 验证码session名
* @param length 验证码字符长度
*/
@Deprecated
public static void generate(
HttpServletRequest request,
HttpServletResponse response,
String id,
String captchaName,
int length
) {
generate(request, response, id, captchaName, length, DEFAULT_CAPTCHA_WIDTH, DEFAULT_CAPTCHA_HEIGHT);
}
/**
* 生成验证码
*
* @param request 请求
* @param response 响应
* @param id 验证码id 初始生成时可不传
* @param captchaName 验证码session名
* @param length 验证码字符长度
* @param width 验证码图片宽度 单位像素
* @param height 验证码图片搞定 单位像素
* @see CaptchaTools#generate(CaptchaRequest captchaRequest)
* @deprecated see CaptchaTools#generate(CaptchaRequest captchaRequest)
*/
@Deprecated
public static void generate(
HttpServletRequest request,
HttpServletResponse response,
String id,
String captchaName,
int length,
int width,
int height
) {
logger.debug("CaptchaTools.generate id={}, length={}", id, length);
try {
System.setProperty("java.awt.headless", "true");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
// 生成随机字串
String verifyCode = VerifyCodeTools.generateVerifyCode(length);
// 存入会话session
HttpSession session = request.getSession(true);
if (StringTools.isBlank(id)) {
id = IdTools.randomShortUUID();
}
Captcha captcha = new Captcha(id, verifyCode.toLowerCase());
session.setAttribute(captchaName, JSON.toJSONString(captcha));
// 生成图片
VerifyCodeTools.outputImage(width, height, response.getOutputStream(), verifyCode);
logger.debug("CaptchaTools.generate: success -> {}", captcha);
} catch (Exception e) {
logger.error("generate error", e);
}
}
/**
* 生成验证码 v2
*
* @param captchaRequest captchaRequest
*/
public static void generate(CaptchaRequest captchaRequest) {
logger.debug("CaptchaTools.generate captchaRequest={}", captchaRequest);
Assert.notNull(captchaRequest, "captchaRequest is null");
HttpServletResponse response = captchaRequest.getResponse();
HttpServletRequest request = captchaRequest.getRequest();
CacheManager cacheManager = captchaRequest.getCacheManager();
String cacheNamespace = captchaRequest.getCacheNamespace();
Assert.notNull(response, "response is null");
Assert.notNull(captchaRequest.getGenerateType(), "generateType is null");
if (CaptchaGenerateType.SESSION.equals(captchaRequest.getGenerateType())) {
Assert.notNull(request, "request is null");
} else if (CaptchaGenerateType.CACHE.equals(captchaRequest.getGenerateType())) {
Assert.notNull(cacheManager, "cacheManager is null");
Assert.notNull(cacheNamespace, "cacheNamespace is null");
}
int length = captchaRequest.getLength();
int width = captchaRequest.getWidth();
int height = captchaRequest.getHeight();
if (length <= 0) {
length = DEFAULT_CAPTCHA_LENGTH;
}
if (width <= 0) {
width = DEFAULT_CAPTCHA_WIDTH;
}
if (height <= 0) {
height = DEFAULT_CAPTCHA_HEIGHT;
}
try {
System.setProperty("java.awt.headless", "true");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
// 生成随机字串
CaptchaCodeResult captchaCodeResult = CaptchaCodeResult.builder().build();
switch (captchaRequest.getCaptchaType()) {
case LETTER_NUM:
captchaCodeResult = VerifyCodeTools.generateLetterNumVerifyCode(length);
break;
case MATH_ADD:
captchaCodeResult = VerifyCodeTools.generateMathAddVerifyCode(captchaRequest.getMathAddStart(),
captchaRequest.getMathAddEnd());
break;
}
String id = captchaRequest.getId();
if (StringTools.isBlank(id)) {
id = IdTools.randomShortUUID();
}
CaptchaV2 captcha = new CaptchaV2(id, captchaCodeResult.getVerifyContent());
if (CaptchaGenerateType.SESSION.equals(captchaRequest.getGenerateType())) {
saveToSession(captchaRequest, captcha);
} else if (CaptchaGenerateType.CACHE.equals(captchaRequest.getGenerateType())) {
saveToCache(captchaRequest, captcha);
}
// 生成图片
VerifyCodeTools.outputImage(width, height,
response.getOutputStream(), captchaCodeResult.getCaptchaContent(), !CaptchaType.MATH_ADD.equals(captchaRequest.getCaptchaType()));
logger.debug("CaptchaTools.generate: success -> {}", captcha);
} catch (Exception e) {
logger.error("generate error", e);
}
}
private static String getKey(String captchaName, String id) {
return String.format("%s_%s", captchaName, id);
}
private static void saveToSession(CaptchaRequest captchaRequest, CaptchaV2 captcha) {
HttpSession session = captchaRequest.getRequest().getSession(true);
String name = captchaRequest.getName();
if (Objects.isNull(name)) {
name = DEFAULT_CAPTCHA_NAME;
}
session.setAttribute(getKey(name, captcha.getId()), JSON.toJSONString(captcha));
}
private static void saveToCache(CaptchaRequest captchaRequest, CaptchaV2 captcha) {
CacheManager cacheManager = captchaRequest.getCacheManager();
Cache cache = cacheManager.getCache(captchaRequest.getCacheNamespace());
String name = captchaRequest.getName();
if (Objects.isNull(name)) {
name = DEFAULT_CAPTCHA_NAME;
}
cache.put(getKey(name, captcha.getId()), captcha);
}
private static CaptchaV2 getFromSession(CaptchaValidate captchaValidate, String captchaName) {
HttpSession session = captchaValidate.getRequest().getSession(true);
String captchaStr = (String) session.getAttribute(getKey(captchaName, captchaValidate.getCaptcha().getId()));
if (StringTools.isBlank(captchaStr))
throw CaptchaException.notInSession();
return JSONObject.parseObject(captchaStr, CaptchaV2.class);
}
private static CaptchaV2 getFromCache(CaptchaValidate captchaValidate, String captchaName) {
CacheManager cacheManager = captchaValidate.getCacheManager();
Cache cache = cacheManager.getCache(captchaValidate.getCacheNamespace());
Cache.ValueWrapper valueWrapper = cache.get(getKey(captchaName, captchaValidate.getCaptcha().getId()));
if (Objects.nonNull(valueWrapper)) {
return (CaptchaV2) valueWrapper.get();
}
return null;
}
private static void removeCaptcha(CaptchaValidate captchaValidate, String captchaName) {
if (CaptchaGenerateType.SESSION.equals(captchaValidate.getGenerateType())) {
removeFromSession(captchaValidate, captchaName);
} else if (CaptchaGenerateType.CACHE.equals(captchaValidate.getGenerateType())) {
removeFromCache(captchaValidate, captchaName);
}
}
private static void removeFromSession(CaptchaValidate captchaValidate, String captchaName) {
HttpSession session = captchaValidate.getRequest().getSession(true);
session.removeAttribute(getKey(captchaName, captchaValidate.getCaptcha().getId()));
}
private static void removeFromCache(CaptchaValidate captchaValidate, String captchaName) {
CacheManager cacheManager = captchaValidate.getCacheManager();
Cache cache = cacheManager.getCache(captchaValidate.getCacheNamespace());
cache.evict(getKey(captchaName, captchaValidate.getCaptcha().getId()));
}
}