mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
优化
This commit is contained in:
@@ -69,7 +69,7 @@ public class Test2 {
|
|||||||
// 用户传来的行为轨迹和进行校验
|
// 用户传来的行为轨迹和进行校验
|
||||||
// - sliderCaptchaTrack为前端传来的滑动轨迹数据
|
// - sliderCaptchaTrack为前端传来的滑动轨迹数据
|
||||||
// - map 为生成验证码时缓存的map数据
|
// - map 为生成验证码时缓存的map数据
|
||||||
boolean check = sliderCaptchaValidator.valid(sliderCaptchaTrack, map);
|
boolean check = sliderCaptchaValidator.valid(imageCaptchaTrack, map);
|
||||||
// 如果只想校验用户是否滑到指定凹槽即可,也可以使用
|
// 如果只想校验用户是否滑到指定凹槽即可,也可以使用
|
||||||
// - 参数1 用户传来的百分比数据
|
// - 参数1 用户传来的百分比数据
|
||||||
// - 参数2 生成滑块是真实的百分比数据
|
// - 参数2 生成滑块是真实的百分比数据
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.common.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2022/5/7 9:04
|
||||||
|
* @Description 图片验证码异常
|
||||||
|
*/
|
||||||
|
public class ImageCaptchaException extends RuntimeException{
|
||||||
|
public ImageCaptchaException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageCaptchaException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageCaptchaException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageCaptchaException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageCaptchaException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
-22
@@ -1,22 +0,0 @@
|
|||||||
package cloud.tianai.captcha.template.slider.common.exception;
|
|
||||||
|
|
||||||
public class SliderCaptchaException extends RuntimeException{
|
|
||||||
public SliderCaptchaException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public SliderCaptchaException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SliderCaptchaException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SliderCaptchaException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SliderCaptchaException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,17 +13,22 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||||||
*/
|
*/
|
||||||
public class FontUtils {
|
public class FontUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取随机文字
|
||||||
|
*
|
||||||
|
* @param random 随机数生成器
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static String getRandomChar(Random random) {
|
public static String getRandomChar(Random random) {
|
||||||
Integer hightPos, lowPos; // 定义高低位
|
Integer heightPos, lowPos; // 定义高低位
|
||||||
hightPos = (176 + Math.abs(random.nextInt(39)));
|
heightPos = (176 + Math.abs(random.nextInt(39)));
|
||||||
lowPos = (161 + Math.abs(random.nextInt(93)));
|
lowPos = (161 + Math.abs(random.nextInt(93)));
|
||||||
byte[] bytes = new byte[2];
|
byte[] bytes = new byte[2];
|
||||||
bytes[0] = hightPos.byteValue();
|
bytes[0] = heightPos.byteValue();
|
||||||
bytes[1] = lowPos.byteValue();
|
bytes[1] = lowPos.byteValue();
|
||||||
return new String(bytes, "GBK");
|
return new String(bytes, "GBK");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -391,7 +391,8 @@ public class CaptchaImageUtils {
|
|||||||
y1 = y2;
|
y1 = y2;
|
||||||
y2 = ty;
|
y2 = ty;
|
||||||
}
|
}
|
||||||
if (random.nextInt(2) == 0) { // 二阶贝塞尔曲线
|
// 二阶贝塞尔曲线
|
||||||
|
if (random.nextInt(2) == 0) {
|
||||||
QuadCurve2D shape = new QuadCurve2D.Double();
|
QuadCurve2D shape = new QuadCurve2D.Double();
|
||||||
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
|
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
|
||||||
g.draw(shape);
|
g.draw(shape);
|
||||||
|
|||||||
-2
@@ -93,8 +93,6 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
-1
@@ -93,7 +93,6 @@ public class StandardRotateImageCaptchaGenerator extends AbstractImageCaptchaGen
|
|||||||
// 随机x, 转换为角度
|
// 随机x, 转换为角度
|
||||||
int randomX = ThreadLocalRandom.current().nextInt(fixedTemplate.getWidth() + 10, targetBackground.getWidth() - 10);
|
int randomX = ThreadLocalRandom.current().nextInt(fixedTemplate.getWidth() + 10, targetBackground.getWidth() - 10);
|
||||||
double degree = 360d - randomX / ((targetBackground.getWidth()) / 360d);
|
double degree = 360d - randomX / ((targetBackground.getWidth()) / 360d);
|
||||||
// int degree = ThreadLocalRandom.current().nextInt(10, 350);
|
|
||||||
centerOverlayAndRotateImage(matrixTemplate, cutImage, degree);
|
centerOverlayAndRotateImage(matrixTemplate, cutImage, degree);
|
||||||
return wrapRotateCaptchaInfo(degree, randomX, targetBackground, matrixTemplate, param);
|
return wrapRotateCaptchaInfo(degree, randomX, targetBackground, matrixTemplate, param);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
+6
@@ -19,5 +19,11 @@ public abstract class AbstractResourceProvider implements ResourceProvider {
|
|||||||
return resourceInputStream;
|
return resourceInputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过 Resource 获取 InputStream
|
||||||
|
*
|
||||||
|
* @param data data
|
||||||
|
* @return InputStream
|
||||||
|
*/
|
||||||
public abstract InputStream doGetResourceInputStream(Resource data);
|
public abstract InputStream doGetResourceInputStream(Resource data);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -16,6 +16,7 @@ public interface ImageCaptchaResourceManager {
|
|||||||
/**
|
/**
|
||||||
* 随机获取某个模板
|
* 随机获取某个模板
|
||||||
*
|
*
|
||||||
|
* @param type 验证码类型
|
||||||
* @return Map<String, Resource>
|
* @return Map<String, Resource>
|
||||||
*/
|
*/
|
||||||
Map<String, Resource> randomGetTemplate(String type);
|
Map<String, Resource> randomGetTemplate(String type);
|
||||||
@@ -23,6 +24,7 @@ public interface ImageCaptchaResourceManager {
|
|||||||
/**
|
/**
|
||||||
* 随机获取某个资源对象
|
* 随机获取某个资源对象
|
||||||
*
|
*
|
||||||
|
* @param type 验证码类型
|
||||||
* @return Resource
|
* @return Resource
|
||||||
*/
|
*/
|
||||||
Resource randomGetResource(String type);
|
Resource randomGetResource(String type);
|
||||||
|
|||||||
@@ -5,11 +5,17 @@ import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2022/5/7 9:04
|
||||||
|
* @Description 资源存储
|
||||||
|
*/
|
||||||
public interface ResourceStore {
|
public interface ResourceStore {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加资源
|
* 添加资源
|
||||||
*
|
*
|
||||||
|
* @param type 验证码类型
|
||||||
* @param resource 资源
|
* @param resource 资源
|
||||||
*/
|
*/
|
||||||
void addResource(String type, Resource resource);
|
void addResource(String type, Resource resource);
|
||||||
@@ -67,7 +73,8 @@ public interface ResourceStore {
|
|||||||
/**
|
/**
|
||||||
* 添加模板
|
* 添加模板
|
||||||
*
|
*
|
||||||
* @param template template
|
* @param type 验证码类型
|
||||||
|
* @param template 模板
|
||||||
*/
|
*/
|
||||||
void addTemplate(String type, Map<String, Resource> template);
|
void addTemplate(String type, Map<String, Resource> template);
|
||||||
|
|
||||||
@@ -86,6 +93,7 @@ public interface ResourceStore {
|
|||||||
/**
|
/**
|
||||||
* 获取所有模板通过type
|
* 获取所有模板通过type
|
||||||
*
|
*
|
||||||
|
* @param type 验证码类型
|
||||||
* @return List<Map < String, Resource>>
|
* @return List<Map < String, Resource>>
|
||||||
*/
|
*/
|
||||||
List<Map<String, Resource>> listTemplatesByType(String type);
|
List<Map<String, Resource>> listTemplatesByType(String type);
|
||||||
|
|||||||
-79
@@ -1,79 +0,0 @@
|
|||||||
package cloud.tianai.captcha.template.slider.resource;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author: 天爱有情
|
|
||||||
* @date 2020/10/19 18:38
|
|
||||||
* @Description 滑块验证码资源
|
|
||||||
*/
|
|
||||||
public interface SliderCaptchaResource {
|
|
||||||
/**
|
|
||||||
* 添加资源
|
|
||||||
*
|
|
||||||
* @param url url
|
|
||||||
*/
|
|
||||||
void addResource(URL url);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置资源
|
|
||||||
*
|
|
||||||
* @param resources resources
|
|
||||||
*/
|
|
||||||
void setResource(List<URL> resources);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除资源
|
|
||||||
*
|
|
||||||
* @param resource resource
|
|
||||||
*/
|
|
||||||
void deleteResource(URL resource);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取所有资源
|
|
||||||
*
|
|
||||||
* @return List<URL>
|
|
||||||
*/
|
|
||||||
List<URL> listResources();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除所有资源
|
|
||||||
*/
|
|
||||||
void clearResources();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加模板
|
|
||||||
*
|
|
||||||
* @param template template
|
|
||||||
*/
|
|
||||||
void addTemplate(Map<String, URL> template);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置模板
|
|
||||||
*
|
|
||||||
* @param imageTemplates imageTemplates
|
|
||||||
*/
|
|
||||||
void setTemplates(List<Map<String, URL>> imageTemplates);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除模板
|
|
||||||
*
|
|
||||||
* @param template template
|
|
||||||
*/
|
|
||||||
void deleteTemplate(Map<String, URL> template);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询所有模板
|
|
||||||
*
|
|
||||||
* @return List<Map < String, URL>>
|
|
||||||
*/
|
|
||||||
List<Map<String, URL>> listTemplates();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除所有模板
|
|
||||||
*/
|
|
||||||
void clearTemplates();
|
|
||||||
}
|
|
||||||
+3
-2
@@ -21,9 +21,10 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class DefaultImageCaptchaResourceManager implements ImageCaptchaResourceManager {
|
public class DefaultImageCaptchaResourceManager implements ImageCaptchaResourceManager {
|
||||||
|
|
||||||
|
/** 资源存储. */
|
||||||
private ResourceStore resourceStore;
|
private ResourceStore resourceStore;
|
||||||
|
/** 资源转换 转换为stream流. */
|
||||||
private List<ResourceProvider> resourceProviderList = new ArrayList<>(8);
|
private final List<ResourceProvider> resourceProviderList = new ArrayList<>(8);
|
||||||
|
|
||||||
|
|
||||||
public DefaultImageCaptchaResourceManager() {
|
public DefaultImageCaptchaResourceManager() {
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
package cloud.tianai.captcha.template.slider.validator;
|
package cloud.tianai.captcha.template.slider.validator;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
import cloud.tianai.captcha.template.slider.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -51,9 +51,9 @@ public interface ImageCaptchaValidator {
|
|||||||
/**
|
/**
|
||||||
* 校验用户滑动滑块是否正确
|
* 校验用户滑动滑块是否正确
|
||||||
*
|
*
|
||||||
* @param sliderCaptchaTrack 包含了滑动轨迹,展示的图片宽高,滑动时间等参数
|
* @param imageCaptchaTrack 包含了滑动轨迹,展示的图片宽高,滑动时间等参数
|
||||||
* @param sliderCaptchaValidData generateSliderCaptchaValidData(生成的数据
|
* @param sliderCaptchaValidData generateSliderCaptchaValidData(生成的数据
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData);
|
boolean valid(ImageCaptchaTrack imageCaptchaTrack, Map<String, Object> sliderCaptchaValidData);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -11,10 +11,10 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
* @date 2022/2/17 9:23
|
* @date 2022/2/17 9:23
|
||||||
* @Description 滑块验证码滑动轨迹
|
* @Description 图片验证码滑动轨迹
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class SliderCaptchaTrack {
|
public class ImageCaptchaTrack {
|
||||||
|
|
||||||
/** 背景图片宽度. */
|
/** 背景图片宽度. */
|
||||||
private Integer bgImageWidth;
|
private Integer bgImageWidth;
|
||||||
@@ -32,7 +32,6 @@ public class SliderCaptchaTrack {
|
|||||||
private List<Track> trackList;
|
private List<Track> trackList;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
//#I4WQ4F
|
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class Track {
|
public static class Track {
|
||||||
+20
-26
@@ -3,7 +3,7 @@ package cloud.tianai.captcha.template.slider.validator.impl;
|
|||||||
import cloud.tianai.captcha.template.slider.common.util.CaptchaUtils;
|
import cloud.tianai.captcha.template.slider.common.util.CaptchaUtils;
|
||||||
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
||||||
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
import cloud.tianai.captcha.template.slider.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -23,23 +23,23 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean beforeValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
public boolean beforeValid(ImageCaptchaTrack imageCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
// 校验参数
|
// 校验参数
|
||||||
checkParam(sliderCaptchaTrack);
|
checkParam(imageCaptchaTrack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean afterValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
public boolean afterValid(ImageCaptchaTrack imageCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
if (!CaptchaUtils.isSliderCaptcha(type)){
|
if (!CaptchaUtils.isSliderCaptcha(type)){
|
||||||
// 不是滑动验证码的话暂时跳过,点选验证码行为轨迹还没做
|
// 不是滑动验证码的话暂时跳过,点选验证码行为轨迹还没做
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 进行行为轨迹检测
|
// 进行行为轨迹检测
|
||||||
long startSlidingTime = sliderCaptchaTrack.getStartSlidingTime().getTime();
|
long startSlidingTime = imageCaptchaTrack.getStartSlidingTime().getTime();
|
||||||
long endSlidingTime = sliderCaptchaTrack.getEntSlidingTime().getTime();
|
long endSlidingTime = imageCaptchaTrack.getEntSlidingTime().getTime();
|
||||||
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
|
Integer bgImageWidth = imageCaptchaTrack.getBgImageWidth();
|
||||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
|
||||||
// 这里只进行基本检测, 用一些简单算法进行校验,如有需要可扩展
|
// 这里只进行基本检测, 用一些简单算法进行校验,如有需要可扩展
|
||||||
// 检测1: 滑动时间如果小于300毫秒 返回false
|
// 检测1: 滑动时间如果小于300毫秒 返回false
|
||||||
// 检测2: 轨迹数据要是少于背10,或者大于背景宽度的五倍 返回false
|
// 检测2: 轨迹数据要是少于背10,或者大于背景宽度的五倍 返回false
|
||||||
@@ -58,14 +58,14 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 检测3
|
// 检测3
|
||||||
SliderCaptchaTrack.Track firstTrack = trackList.get(0);
|
ImageCaptchaTrack.Track firstTrack = trackList.get(0);
|
||||||
if (firstTrack.getX() > 10 || firstTrack.getX() < -10 || firstTrack.getY() > 10 || firstTrack.getY() < -10) {
|
if (firstTrack.getX() > 10 || firstTrack.getX() < -10 || firstTrack.getY() > 10 || firstTrack.getY() < -10) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int check4 = 0;
|
int check4 = 0;
|
||||||
int check7 = 0;
|
int check7 = 0;
|
||||||
for (int i = 1; i < trackList.size(); i++) {
|
for (int i = 1; i < trackList.size(); i++) {
|
||||||
SliderCaptchaTrack.Track track = trackList.get(i);
|
ImageCaptchaTrack.Track track = trackList.get(i);
|
||||||
int x = track.getX();
|
int x = track.getX();
|
||||||
int y = track.getY();
|
int y = track.getY();
|
||||||
// check4
|
// check4
|
||||||
@@ -77,7 +77,7 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
|||||||
check7++;
|
check7++;
|
||||||
}
|
}
|
||||||
// check5
|
// check5
|
||||||
SliderCaptchaTrack.Track preTrack = trackList.get(i - 1);
|
ImageCaptchaTrack.Track preTrack = trackList.get(i - 1);
|
||||||
if ((track.getX() - preTrack.getX()) > 50 || (track.getY() - preTrack.getY()) > 50) {
|
if ((track.getX() - preTrack.getX()) > 50 || (track.getY() - preTrack.getY()) > 50) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -88,39 +88,33 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
|||||||
|
|
||||||
// check6
|
// check6
|
||||||
int splitPos = (int) (trackList.size() * 0.7);
|
int splitPos = (int) (trackList.size() * 0.7);
|
||||||
SliderCaptchaTrack.Track splitPostTrack = trackList.get(splitPos - 1);
|
ImageCaptchaTrack.Track splitPostTrack = trackList.get(splitPos - 1);
|
||||||
int posTime = splitPostTrack.getT();
|
int posTime = splitPostTrack.getT();
|
||||||
float startAvgPosTime = posTime / (float) splitPos;
|
float startAvgPosTime = posTime / (float) splitPos;
|
||||||
|
|
||||||
SliderCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
|
ImageCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
|
||||||
float endAvgPosTime = lastTrack.getT() / (float) (trackList.size() - splitPos);
|
float endAvgPosTime = lastTrack.getT() / (float) (trackList.size() - splitPos);
|
||||||
|
|
||||||
return endAvgPosTime > startAvgPosTime;
|
return endAvgPosTime > startAvgPosTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkParam(SliderCaptchaTrack sliderCaptchaTrack) {
|
public void checkParam(ImageCaptchaTrack imageCaptchaTrack) {
|
||||||
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getBgImageWidth())) {
|
if (ObjectUtils.isEmpty(imageCaptchaTrack.getBgImageWidth())) {
|
||||||
throw new IllegalArgumentException("bgImageWidth must not be null");
|
throw new IllegalArgumentException("bgImageWidth must not be null");
|
||||||
}
|
}
|
||||||
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getBgImageHeight())) {
|
if (ObjectUtils.isEmpty(imageCaptchaTrack.getBgImageHeight())) {
|
||||||
throw new IllegalArgumentException("bgImageHeight must not be null");
|
throw new IllegalArgumentException("bgImageHeight must not be null");
|
||||||
}
|
}
|
||||||
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getSliderImageWidth())) {
|
if (ObjectUtils.isEmpty(imageCaptchaTrack.getStartSlidingTime())) {
|
||||||
throw new IllegalArgumentException("sliderImageWidth must not be null");
|
|
||||||
}
|
|
||||||
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getSliderImageHeight())) {
|
|
||||||
throw new IllegalArgumentException("sliderImageHeight must not be null");
|
|
||||||
}
|
|
||||||
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getStartSlidingTime())) {
|
|
||||||
throw new IllegalArgumentException("startSlidingTime must not be null");
|
throw new IllegalArgumentException("startSlidingTime must not be null");
|
||||||
}
|
}
|
||||||
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getEntSlidingTime())) {
|
if (ObjectUtils.isEmpty(imageCaptchaTrack.getEntSlidingTime())) {
|
||||||
throw new IllegalArgumentException("entSlidingTime must not be null");
|
throw new IllegalArgumentException("entSlidingTime must not be null");
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isEmpty(sliderCaptchaTrack.getTrackList())) {
|
if (CollectionUtils.isEmpty(imageCaptchaTrack.getTrackList())) {
|
||||||
throw new IllegalArgumentException("trackList must not be null");
|
throw new IllegalArgumentException("trackList must not be null");
|
||||||
}
|
}
|
||||||
for (SliderCaptchaTrack.Track track : sliderCaptchaTrack.getTrackList()) {
|
for (ImageCaptchaTrack.Track track : imageCaptchaTrack.getTrackList()) {
|
||||||
Integer x = track.getX();
|
Integer x = track.getX();
|
||||||
Integer y = track.getY();
|
Integer y = track.getY();
|
||||||
Integer t = track.getT();
|
Integer t = track.getT();
|
||||||
|
|||||||
+31
-27
@@ -8,7 +8,7 @@ import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImag
|
|||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.validator.ImageCaptchaValidator;
|
import cloud.tianai.captcha.template.slider.validator.ImageCaptchaValidator;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.constant.TrackTypeConstant;
|
import cloud.tianai.captcha.template.slider.validator.common.constant.TrackTypeConstant;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
import cloud.tianai.captcha.template.slider.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -26,9 +26,13 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||||
|
|
||||||
|
/** 默认的容错值. */
|
||||||
public static float DEFAULT_TOLERANT = 0.02f;
|
public static float DEFAULT_TOLERANT = 0.02f;
|
||||||
|
/** 验证数据 key. */
|
||||||
public static final String PERCENTAGE_KEY = "percentage";
|
public static final String PERCENTAGE_KEY = "percentage";
|
||||||
|
/** 容错值key. */
|
||||||
public static final String TOLERANT_KEY = "tolerant";
|
public static final String TOLERANT_KEY = "tolerant";
|
||||||
|
/** 类型 key, 标识是哪张类型的验证码. */
|
||||||
public static final String TYPE_KEY = "type";
|
public static final String TYPE_KEY = "type";
|
||||||
|
|
||||||
/** 容错值. */
|
/** 容错值. */
|
||||||
@@ -68,7 +72,7 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Object> generateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
public Map<String, Object> generateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
||||||
Map<String, Object> map = new HashMap<>(8);
|
Map<String, Object> map = new HashMap<>(8);
|
||||||
if(beforeGenerateImageCaptchaValidData(imageCaptchaInfo, map)) {
|
if (beforeGenerateImageCaptchaValidData(imageCaptchaInfo, map)) {
|
||||||
doGenerateImageCaptchaValidData(map, imageCaptchaInfo);
|
doGenerateImageCaptchaValidData(map, imageCaptchaInfo);
|
||||||
}
|
}
|
||||||
afterGenerateImageCaptchaValidData(imageCaptchaInfo, map);
|
afterGenerateImageCaptchaValidData(imageCaptchaInfo, map);
|
||||||
@@ -136,30 +140,30 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
public boolean valid(ImageCaptchaTrack imageCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
||||||
// 读容错值
|
// 读容错值
|
||||||
Float tolerant = getFloatParam(TOLERANT_KEY, sliderCaptchaValidData, defaultTolerant);
|
Float tolerant = getFloatParam(TOLERANT_KEY, sliderCaptchaValidData, defaultTolerant);
|
||||||
// 读验证码类型
|
// 读验证码类型
|
||||||
String type = getStringParam(TYPE_KEY, sliderCaptchaValidData, CaptchaTypeConstant.SLIDER);
|
String type = getStringParam(TYPE_KEY, sliderCaptchaValidData, CaptchaTypeConstant.SLIDER);
|
||||||
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
|
Integer bgImageWidth = imageCaptchaTrack.getBgImageWidth();
|
||||||
if (bgImageWidth == null || bgImageWidth < 1) {
|
if (bgImageWidth == null || bgImageWidth < 1) {
|
||||||
// 没有背景图片宽度
|
// 没有背景图片宽度
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
|
||||||
if (CollectionUtils.isEmpty(trackList)) {
|
if (CollectionUtils.isEmpty(trackList)) {
|
||||||
// 没有滑动轨迹
|
// 没有滑动轨迹
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 验证前
|
// 验证前
|
||||||
if (!beforeValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type)) {
|
if (!beforeValid(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 验证
|
// 验证
|
||||||
boolean valid = doValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
boolean valid = doValid(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
// 验证后
|
// 验证后
|
||||||
valid = afterValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
valid = afterValid(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
@@ -167,39 +171,39 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
/**
|
/**
|
||||||
* 验证前
|
* 验证前
|
||||||
*
|
*
|
||||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
* @param imageCaptchaTrack sliderCaptchaTrack
|
||||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
* @param tolerant tolerant
|
* @param tolerant tolerant
|
||||||
* @param type type
|
* @param type type
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public boolean beforeValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
public boolean beforeValid(ImageCaptchaTrack imageCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证后
|
* 验证后
|
||||||
*
|
*
|
||||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
* @param imageCaptchaTrack sliderCaptchaTrack
|
||||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
* @param tolerant tolerant
|
* @param tolerant tolerant
|
||||||
* @param type type
|
* @param type type
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public boolean afterValid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
public boolean afterValid(ImageCaptchaTrack imageCaptchaTrack, Map<String, Object> sliderCaptchaValidData, Float tolerant, String type) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean doValid(SliderCaptchaTrack sliderCaptchaTrack,
|
public boolean doValid(ImageCaptchaTrack imageCaptchaTrack,
|
||||||
Map<String, Object> sliderCaptchaValidData,
|
Map<String, Object> sliderCaptchaValidData,
|
||||||
Float tolerant,
|
Float tolerant,
|
||||||
String type) {
|
String type) {
|
||||||
if (CaptchaUtils.isSliderCaptcha(type)) {
|
if (CaptchaUtils.isSliderCaptcha(type)) {
|
||||||
// 滑动类型验证码
|
// 滑动类型验证码
|
||||||
return doValidSliderCaptcha(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
return doValidSliderCaptcha(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||||
} else if (CaptchaUtils.isClickCaptcha(type)) {
|
} else if (CaptchaUtils.isClickCaptcha(type)) {
|
||||||
// 点选类型验证码
|
// 点选类型验证码
|
||||||
return doValidClickCaptcha(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
return doValidClickCaptcha(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||||
}
|
}
|
||||||
// 不支持的类型
|
// 不支持的类型
|
||||||
log.warn("校验验证码警告, 不支持的验证码类型:{}, 请手动扩展 cloud.tianai.captcha.template.slider.validator.impl.SimpleImageCaptchaValidator.doValid 进行校验扩展", type);
|
log.warn("校验验证码警告, 不支持的验证码类型:{}, 请手动扩展 cloud.tianai.captcha.template.slider.validator.impl.SimpleImageCaptchaValidator.doValid 进行校验扩展", type);
|
||||||
@@ -209,13 +213,13 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
/**
|
/**
|
||||||
* 校验点选验证码
|
* 校验点选验证码
|
||||||
*
|
*
|
||||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
* @param imageCaptchaTrack sliderCaptchaTrack
|
||||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
* @param tolerant tolerant
|
* @param tolerant tolerant
|
||||||
* @param type type
|
* @param type type
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public boolean doValidClickCaptcha(SliderCaptchaTrack sliderCaptchaTrack,
|
public boolean doValidClickCaptcha(ImageCaptchaTrack imageCaptchaTrack,
|
||||||
Map<String, Object> sliderCaptchaValidData,
|
Map<String, Object> sliderCaptchaValidData,
|
||||||
Float tolerant,
|
Float tolerant,
|
||||||
String type) {
|
String type) {
|
||||||
@@ -224,12 +228,12 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String[] splitArr = validStr.split(";");
|
String[] splitArr = validStr.split(";");
|
||||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
|
||||||
if (trackList.size() < splitArr.length) {
|
if (trackList.size() < splitArr.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 取出点击事件的轨迹数据
|
// 取出点击事件的轨迹数据
|
||||||
List<SliderCaptchaTrack.Track> clickTrackList = trackList
|
List<ImageCaptchaTrack.Track> clickTrackList = trackList
|
||||||
.stream()
|
.stream()
|
||||||
.filter(t -> TrackTypeConstant.CLICK.equalsIgnoreCase(t.getType()))
|
.filter(t -> TrackTypeConstant.CLICK.equalsIgnoreCase(t.getType()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@@ -237,14 +241,14 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < splitArr.length; i++) {
|
for (int i = 0; i < splitArr.length; i++) {
|
||||||
SliderCaptchaTrack.Track track = clickTrackList.get(i);
|
ImageCaptchaTrack.Track track = clickTrackList.get(i);
|
||||||
String posStr = splitArr[i];
|
String posStr = splitArr[i];
|
||||||
String[] posArr = posStr.split(",");
|
String[] posArr = posStr.split(",");
|
||||||
float xPercentage = Float.parseFloat(posArr[0]);
|
float xPercentage = Float.parseFloat(posArr[0]);
|
||||||
float yPercentage = Float.parseFloat(posArr[1]);
|
float yPercentage = Float.parseFloat(posArr[1]);
|
||||||
|
|
||||||
float calcXPercentage = calcPercentage(track.getX(), sliderCaptchaTrack.getBgImageWidth());
|
float calcXPercentage = calcPercentage(track.getX(), imageCaptchaTrack.getBgImageWidth());
|
||||||
float calcYPercentage = calcPercentage(track.getY(), sliderCaptchaTrack.getBgImageHeight());
|
float calcYPercentage = calcPercentage(track.getY(), imageCaptchaTrack.getBgImageHeight());
|
||||||
|
|
||||||
if (!checkPercentage(calcXPercentage, xPercentage, tolerant)
|
if (!checkPercentage(calcXPercentage, xPercentage, tolerant)
|
||||||
|| !checkPercentage(calcYPercentage, yPercentage, tolerant)) {
|
|| !checkPercentage(calcYPercentage, yPercentage, tolerant)) {
|
||||||
@@ -257,13 +261,13 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
/**
|
/**
|
||||||
* 校验滑动验证码
|
* 校验滑动验证码
|
||||||
*
|
*
|
||||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
* @param imageCaptchaTrack sliderCaptchaTrack
|
||||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||||
* @param tolerant tolerant
|
* @param tolerant tolerant
|
||||||
* @param type type
|
* @param type type
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public boolean doValidSliderCaptcha(SliderCaptchaTrack sliderCaptchaTrack,
|
public boolean doValidSliderCaptcha(ImageCaptchaTrack imageCaptchaTrack,
|
||||||
Map<String, Object> sliderCaptchaValidData,
|
Map<String, Object> sliderCaptchaValidData,
|
||||||
Float tolerant,
|
Float tolerant,
|
||||||
String type) {
|
String type) {
|
||||||
@@ -272,11 +276,11 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
|||||||
// 没读取到百分比
|
// 没读取到百分比
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
|
||||||
// 取最后一个滑动轨迹
|
// 取最后一个滑动轨迹
|
||||||
SliderCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
|
ImageCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
|
||||||
// 计算百分比
|
// 计算百分比
|
||||||
float calcPercentage = calcPercentage(lastTrack.getX(), sliderCaptchaTrack.getBgImageWidth());
|
float calcPercentage = calcPercentage(lastTrack.getX(), imageCaptchaTrack.getBgImageWidth());
|
||||||
// 校验百分比
|
// 校验百分比
|
||||||
return checkPercentage(calcPercentage, oriPercentage, tolerant);
|
return checkPercentage(calcPercentage, oriPercentage, tolerant);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user