Commit 7da31688 authored by 技术部-任文超's avatar 技术部-任文超

重构QG-Test(量化派图形验证码)的service和校验切面

parent adb404b0
......@@ -98,5 +98,7 @@ public interface Constants {
String FN_GEETEST_CHALLENGE = "geetest_challenge";
String FN_GEETEST_VALIDATE = "geetest_validate";
String FN_GEETEST_SECCODE = "geetest_seccode";
String GEETEST_CAPTCHA_STATUS = "success";
String TEST_PARAM = "testType";
String TEST_TYPE_GT = "gt";
String TEST_TYPE_QG = "qg";
}
......@@ -2,7 +2,8 @@ package cn.quantgroup.xyqb.aspect.captcha;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.service.captcha.geetest.IGeetestCaptchaService;
import cn.quantgroup.xyqb.service.captcha.IGeetestCaptchaService;
import cn.quantgroup.xyqb.service.captcha.IQuantgroupCaptchaService;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService;
import cn.quantgroup.xyqb.util.IPUtil;
import cn.quantgroup.xyqb.util.PasswordUtil;
......@@ -22,6 +23,7 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
......@@ -32,29 +34,17 @@ import java.util.UUID;
@Component
@Slf4j
public class CaptchaNewValidateAdvisor {
private static final String SUPER_CAPTCHA_ID = UUID.nameUUIDFromBytes("__QG_APPCLIENT_AGENT__".getBytes(Charset.forName("UTF-8"))).toString();
private static final String SUPER_CAPTCHA = "__SUPERQG__";
@Resource
private IGeetestCaptchaService geetestCaptchaService;
@Resource
@Qualifier("customCaptchaService")
private AbstractManageableImageCaptchaService imageCaptchaService;
/**
* 自动化测试忽略验证码
*/
@Value("${xyqb.auth.captcha.autotest.enable:false}")
private boolean autoTestCaptchaEnabled;
private IQuantgroupCaptchaService quantgroupCaptchaService;
/**
* 图形验证码切面
*/
@Pointcut("@annotation(cn.quantgroup.xyqb.aspect.captcha.CaptchaNewValidator)")
private void needCaptchaValidate() {
}
private void needCaptchaValidate(){}
/**
* 在受图形验证码保护的接口方法执行前, 执行图形验证码校验
......@@ -66,53 +56,48 @@ public class CaptchaNewValidateAdvisor {
@Around("needCaptchaValidate()")
private Object doCaptchaValidate(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
if (Constants.GT_CAPTCHA_UNUSER.equals(request.getParameter(Constants.GEETEST_CAPTCHA_STATUS))) {
//极验不可用,用QG
if (isQuantgroupCaptchaValidateSuccess(request)) {
// 验证码类别:gt - 极验,qg - 量化派图形验证
if (Objects.equals(Constants.TEST_TYPE_GT, request.getParameter(Constants.TEST_PARAM))) {
if(gtValid(request)){
return pjp.proceed();
} else {
return JsonResult.buildErrorStateResult("图形验证码有误", "");
}else{
return JsonResult.buildErrorStateResult("验证码有误", "");
}
} else {
String challenge = request.getParameter(Constants.FN_GEETEST_CHALLENGE);
String validate = request.getParameter(Constants.FN_GEETEST_VALIDATE);
String seccode = request.getParameter(Constants.FN_GEETEST_SECCODE);
String phoneNo = request.getParameter("phoneNo");
String clientType = request.getParameter("clientType");
geetestCaptchaService.captchaValidate(clientType, PasswordUtil.MD5(phoneNo), IPUtil.getRemoteIP(request), challenge, validate, seccode);
log.info("使用极验二次验证,phoneNo:{}", phoneNo);
if (qgValid(request)) {
return pjp.proceed();
} else {
return JsonResult.buildErrorStateResult("验证码有误", "");
}
}
return pjp.proceed();
}
private Boolean isQuantgroupCaptchaValidateSuccess(HttpServletRequest request) throws Throwable {
String registerFrom = Optional.ofNullable(request.getParameter("registerFrom")).orElse("");
String captchaId = Optional.ofNullable(request.getParameter("captchaId")).orElse("");
String captchaValue = request.getParameter("captchaValue");
if (isSkipCaptchaValidate(captchaId, captchaValue)) {
log.info("使用超级图形验证码校验, registerFrom={}, clientIp={}", registerFrom, IPUtil.getRemoteIP(request));
return Boolean.TRUE;
}
Boolean validCaptcha = false;
if (StringUtils.isNotBlank(captchaValue)) {
// 忽略用户输入的大小写
String captcha = StringUtils.lowerCase(captchaValue);
// 验证码校验
try {
validCaptcha = imageCaptchaService.validateResponseForID(Constants.IMAGE_CAPTCHA_KEY + captchaId, captcha);
} catch (CaptchaServiceException ex) {
log.error("验证码校验异常, {}, {}", ex.getMessage(), ex);
}
}
return validCaptcha;
/**
* 极验校验
* @param request
* @return
* @throws Throwable
*/
private boolean gtValid(HttpServletRequest request) {
String challenge = request.getParameter(Constants.FN_GEETEST_CHALLENGE);
String validate = request.getParameter(Constants.FN_GEETEST_VALIDATE);
String seccode = request.getParameter(Constants.FN_GEETEST_SECCODE);
String phoneNo = request.getParameter("phoneNo");
String clientType = request.getParameter("clientType");
log.info("使用极验二次验证,phoneNo:{}", phoneNo);
return 0 == geetestCaptchaService.captchaValidate(clientType, PasswordUtil.MD5(phoneNo), IPUtil.getRemoteIP(request), challenge, validate, seccode);
}
private boolean isSkipCaptchaValidate(String captchaId, Object captchaValue) {
// 如果启用了超级验证码功能, 检查超级验证码, 超级验证码区分大小写
return autoTestCaptchaEnabled || org.apache.commons.lang3.StringUtils.equals(SUPER_CAPTCHA_ID, String.valueOf(captchaId))
&& org.apache.commons.lang3.StringUtils.equals(SUPER_CAPTCHA, String.valueOf(captchaValue));
/**
* 量化派图形码校验
* @param request
* @return
* @throws Throwable
*/
private boolean qgValid(HttpServletRequest request) {
String captchaId = Optional.ofNullable(request.getParameter("captchaId")).orElse("");
String captchaValue = request.getParameter("captchaValue");
return quantgroupCaptchaService.validCaptcha(captchaId, captchaValue);
}
}
......@@ -4,8 +4,8 @@ import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.aspect.captcha.CaptchaNewValidator;
import cn.quantgroup.xyqb.aspect.logcaller.LogHttpCaller;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.service.captcha.geetest.IGeetestCaptchaService;
import cn.quantgroup.xyqb.service.captcha.qg.IQuantgroupCaptchaService;
import cn.quantgroup.xyqb.service.captcha.IGeetestCaptchaService;
import cn.quantgroup.xyqb.service.captcha.IQuantgroupCaptchaService;
import cn.quantgroup.xyqb.util.IPUtil;
import cn.quantgroup.xyqb.util.PasswordUtil;
import cn.quantgroup.xyqb.util.ValidationUtil;
......
package cn.quantgroup.xyqb.service.captcha.geetest;
package cn.quantgroup.xyqb.service.captcha;
/**
* @author xufei on 2018/1/30.
......
package cn.quantgroup.xyqb.service.captcha.qg;
package cn.quantgroup.xyqb.service.captcha;
import java.util.Locale;
import java.util.Map;
/**
* @author xufei on 2018/1/30.
*/
public interface IQuantgroupCaptchaService {
/**
* QG获取验证码
*
* 获取QG验证码
* @param locale
* @return
* @throws Exception EX
*/
String fetchCaptcha(Locale locale) throws Exception;
Map<String, String> fetchCaptcha(Locale locale);
/**
* 校验QG验证码
* @param key
* @param code
* @return
*/
boolean validCaptcha(String key, String code);
}
package cn.quantgroup.xyqb.service.captcha.geetest;
package cn.quantgroup.xyqb.service.captcha.impl;
import cn.quantgroup.xyqb.service.captcha.geetest.sdk.GeetestLib;
import cn.quantgroup.xyqb.service.captcha.IGeetestCaptchaService;
import cn.quantgroup.xyqb.service.captcha.impl.sdk.GeetestLib;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
......
package cn.quantgroup.xyqb.service.captcha.qg;
package cn.quantgroup.xyqb.service.captcha.impl;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.service.captcha.IQuantgroupCaptchaService;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService;
import com.octo.captcha.service.CaptchaServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
......@@ -12,40 +17,57 @@ import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
/**
* @author xufei on 2018/1/30.
*/
@Slf4j
@Service
public class QuantgroupCaptchaServiceImpl implements IQuantgroupCaptchaService {
private static final String IMAGE_FORMAT_PNG = "png";
private static final String IMG_BASE64_PATTREN = "data:image/" + IMAGE_FORMAT_PNG + ";base64,%s";
/**
* 自动化测试忽略验证码
*/
@Value("${xyqb.auth.captcha.autotest.enable:false}")
private boolean autoTestCaptchaEnabled;
@Autowired
@Qualifier("customCaptchaService")
private AbstractManageableImageCaptchaService imageCaptchaService;
@Override
public String fetchCaptcha(Locale locale) throws Exception {
public Map<String, String> fetchCaptcha(Locale locale) {
Map<String, String> data = new HashMap<>();
data.put(Constants.TEST_PARAM, Constants.TEST_TYPE_QG);
String imageId = UUID.randomUUID().toString();
BufferedImage challenge = imageCaptchaService.getImageChallengeForID(Constants.IMAGE_CAPTCHA_KEY + imageId, locale);
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
ImageIO.write(challenge, IMAGE_FORMAT_PNG, jpegOutputStream);
try {
ImageIO.write(challenge, IMAGE_FORMAT_PNG, jpegOutputStream);
} catch (IOException e) {
log.error("生成QG图形验证码", e);
return data;
}
String imageBase64 = Base64.encodeBase64String(jpegOutputStream.toByteArray());
data.put("imageId", imageId);
data.put("image", String.format(IMG_BASE64_PATTREN, imageBase64));
return data;
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("success","0");
jsonObject.put("imageId", imageId);
jsonObject.put("image", String.format(IMG_BASE64_PATTREN, imageBase64));
return jsonObject.toString();
@Override
public boolean validCaptcha(String key, String code) {
Boolean validCaptcha = false;
if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(code)) {
// 验证码校验(忽略用户输入的大小写)
try {
validCaptcha = imageCaptchaService.validateResponseForID(Constants.IMAGE_CAPTCHA_KEY + key, code.toLowerCase());
} catch (CaptchaServiceException e) {
log.error("校验QG图形验证码:key:{}, code:{}", key, code, e);
}
}
return validCaptcha;
}
}
package cn.quantgroup.xyqb.service.captcha.geetest.sdk;
package cn.quantgroup.xyqb.service.captcha.impl.sdk;
import cn.quantgroup.xyqb.Constants;
import org.json.JSONException;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment