This commit is contained in:
天爱有情
2022-05-07 09:47:09 +08:00
parent a4e0def76b
commit d802fd481a
16 changed files with 117 additions and 174 deletions
+1 -1
View File
@@ -69,7 +69,7 @@ public class Test2 {
// 用户传来的行为轨迹和进行校验
// - sliderCaptchaTrack为前端传来的滑动轨迹数据
// - map 为生成验证码时缓存的map数据
boolean check = sliderCaptchaValidator.valid(sliderCaptchaTrack, map);
boolean check = sliderCaptchaValidator.valid(imageCaptchaTrack, map);
// 如果只想校验用户是否滑到指定凹槽即可,也可以使用
// - 参数1 用户传来的百分比数据
// - 参数2 生成滑块是真实的百分比数据
@@ -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);
}
}
@@ -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 {
/**
* 获取随机文字
*
* @param random 随机数生成器
* @return String
*/
@SneakyThrows
public static String getRandomChar(Random random) {
Integer hightPos, lowPos; // 定义高低位
hightPos = (176 + Math.abs(random.nextInt(39)));
Integer heightPos, lowPos; // 定义高低位
heightPos = (176 + Math.abs(random.nextInt(39)));
lowPos = (161 + Math.abs(random.nextInt(93)));
byte[] bytes = new byte[2];
bytes[0] = hightPos.byteValue();
bytes[0] = heightPos.byteValue();
bytes[1] = lowPos.byteValue();
return new String(bytes, "GBK");
}
}
@@ -391,7 +391,8 @@ public class CaptchaImageUtils {
y1 = y2;
y2 = ty;
}
if (random.nextInt(2) == 0) { // 二阶贝塞尔曲线
// 二阶贝塞尔曲线
if (random.nextInt(2) == 0) {
QuadCurve2D shape = new QuadCurve2D.Double();
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
g.draw(shape);
@@ -93,8 +93,6 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
}
}
}
// return null;
}
@@ -93,7 +93,6 @@ public class StandardRotateImageCaptchaGenerator extends AbstractImageCaptchaGen
// 随机x 转换为角度
int randomX = ThreadLocalRandom.current().nextInt(fixedTemplate.getWidth() + 10, targetBackground.getWidth() - 10);
double degree = 360d - randomX / ((targetBackground.getWidth()) / 360d);
// int degree = ThreadLocalRandom.current().nextInt(10, 350);
centerOverlayAndRotateImage(matrixTemplate, cutImage, degree);
return wrapRotateCaptchaInfo(degree, randomX, targetBackground, matrixTemplate, param);
} finally {
@@ -19,5 +19,11 @@ public abstract class AbstractResourceProvider implements ResourceProvider {
return resourceInputStream;
}
/**
* 通过 Resource 获取 InputStream
*
* @param data data
* @return InputStream
*/
public abstract InputStream doGetResourceInputStream(Resource data);
}
@@ -16,6 +16,7 @@ public interface ImageCaptchaResourceManager {
/**
* 随机获取某个模板
*
* @param type 验证码类型
* @return Map<String, Resource>
*/
Map<String, Resource> randomGetTemplate(String type);
@@ -23,6 +24,7 @@ public interface ImageCaptchaResourceManager {
/**
* 随机获取某个资源对象
*
* @param type 验证码类型
* @return Resource
*/
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.Map;
/**
* @Author: 天爱有情
* @date 2022/5/7 9:04
* @Description 资源存储
*/
public interface ResourceStore {
/**
* 添加资源
*
* @param type 验证码类型
* @param 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);
@@ -86,6 +93,7 @@ public interface ResourceStore {
/**
* 获取所有模板通过type
*
* @param type 验证码类型
* @return List<Map < String, Resource>>
*/
List<Map<String, Resource>> listTemplatesByType(String type);
@@ -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();
}
@@ -21,9 +21,10 @@ import java.util.Map;
*/
public class DefaultImageCaptchaResourceManager implements ImageCaptchaResourceManager {
/** 资源存储. */
private ResourceStore resourceStore;
private List<ResourceProvider> resourceProviderList = new ArrayList<>(8);
/** 资源转换 转换为stream流. */
private final List<ResourceProvider> resourceProviderList = new ArrayList<>(8);
public DefaultImageCaptchaResourceManager() {
@@ -1,7 +1,7 @@
package cloud.tianai.captcha.template.slider.validator;
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;
@@ -51,9 +51,9 @@ public interface ImageCaptchaValidator {
/**
* 校验用户滑动滑块是否正确
*
* @param sliderCaptchaTrack 包含了滑动轨迹,展示的图片宽高,滑动时间等参数
* @param imageCaptchaTrack 包含了滑动轨迹,展示的图片宽高,滑动时间等参数
* @param sliderCaptchaValidData generateSliderCaptchaValidData(生成的数据
* @return boolean
*/
boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData);
boolean valid(ImageCaptchaTrack imageCaptchaTrack, Map<String, Object> sliderCaptchaValidData);
}
@@ -11,10 +11,10 @@ import java.util.List;
/**
* @Author: 天爱有情
* @date 2022/2/17 9:23
* @Description 滑块验证码滑动轨迹
* @Description 图片验证码滑动轨迹
*/
@Data
public class SliderCaptchaTrack {
public class ImageCaptchaTrack {
/** 背景图片宽度. */
private Integer bgImageWidth;
@@ -32,7 +32,6 @@ public class SliderCaptchaTrack {
private List<Track> trackList;
@Data
//#I4WQ4F
@NoArgsConstructor
@AllArgsConstructor
public static class Track {
@@ -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.CollectionUtils;
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.Map;
@@ -23,23 +23,23 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
}
@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;
}
@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)){
// 不是滑动验证码的话暂时跳过,点选验证码行为轨迹还没做
return true;
}
// 进行行为轨迹检测
long startSlidingTime = sliderCaptchaTrack.getStartSlidingTime().getTime();
long endSlidingTime = sliderCaptchaTrack.getEntSlidingTime().getTime();
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
long startSlidingTime = imageCaptchaTrack.getStartSlidingTime().getTime();
long endSlidingTime = imageCaptchaTrack.getEntSlidingTime().getTime();
Integer bgImageWidth = imageCaptchaTrack.getBgImageWidth();
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
// 这里只进行基本检测, 用一些简单算法进行校验,如有需要可扩展
// 检测1: 滑动时间如果小于300毫秒 返回false
// 检测2: 轨迹数据要是少于背10,或者大于背景宽度的五倍 返回false
@@ -58,14 +58,14 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
return false;
}
// 检测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) {
return false;
}
int check4 = 0;
int check7 = 0;
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 y = track.getY();
// check4
@@ -77,7 +77,7 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
check7++;
}
// 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) {
return false;
}
@@ -88,39 +88,33 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
// check6
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();
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);
return endAvgPosTime > startAvgPosTime;
}
public void checkParam(SliderCaptchaTrack sliderCaptchaTrack) {
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getBgImageWidth())) {
public void checkParam(ImageCaptchaTrack imageCaptchaTrack) {
if (ObjectUtils.isEmpty(imageCaptchaTrack.getBgImageWidth())) {
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");
}
if (ObjectUtils.isEmpty(sliderCaptchaTrack.getSliderImageWidth())) {
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())) {
if (ObjectUtils.isEmpty(imageCaptchaTrack.getStartSlidingTime())) {
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");
}
if (CollectionUtils.isEmpty(sliderCaptchaTrack.getTrackList())) {
if (CollectionUtils.isEmpty(imageCaptchaTrack.getTrackList())) {
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 y = track.getY();
Integer t = track.getT();
@@ -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.validator.ImageCaptchaValidator;
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.Setter;
import lombok.extern.slf4j.Slf4j;
@@ -26,9 +26,13 @@ import java.util.stream.Collectors;
@Slf4j
public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
/** 默认的容错值. */
public static float DEFAULT_TOLERANT = 0.02f;
/** 验证数据 key. */
public static final String PERCENTAGE_KEY = "percentage";
/** 容错值key. */
public static final String TOLERANT_KEY = "tolerant";
/** 类型 key, 标识是哪张类型的验证码. */
public static final String TYPE_KEY = "type";
/** 容错值. */
@@ -68,7 +72,7 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
@Override
public Map<String, Object> generateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
Map<String, Object> map = new HashMap<>(8);
if(beforeGenerateImageCaptchaValidData(imageCaptchaInfo, map)) {
if (beforeGenerateImageCaptchaValidData(imageCaptchaInfo, map)) {
doGenerateImageCaptchaValidData(map, imageCaptchaInfo);
}
afterGenerateImageCaptchaValidData(imageCaptchaInfo, map);
@@ -136,30 +140,30 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
}
@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);
// 读验证码类型
String type = getStringParam(TYPE_KEY, sliderCaptchaValidData, CaptchaTypeConstant.SLIDER);
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
Integer bgImageWidth = imageCaptchaTrack.getBgImageWidth();
if (bgImageWidth == null || bgImageWidth < 1) {
// 没有背景图片宽度
return false;
}
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
if (CollectionUtils.isEmpty(trackList)) {
// 没有滑动轨迹
return false;
}
// 验证前
if (!beforeValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type)) {
if (!beforeValid(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type)) {
return false;
}
// 验证
boolean valid = doValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
boolean valid = doValid(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type);
if (valid) {
// 验证后
valid = afterValid(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
valid = afterValid(imageCaptchaTrack, sliderCaptchaValidData, tolerant, type);
}
return valid;
}
@@ -167,39 +171,39 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
/**
* 验证前
*
* @param sliderCaptchaTrack sliderCaptchaTrack
* @param imageCaptchaTrack sliderCaptchaTrack
* @param sliderCaptchaValidData sliderCaptchaValidData
* @param tolerant tolerant
* @param type type
* @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;
}
/**
* 验证后
*
* @param sliderCaptchaTrack sliderCaptchaTrack
* @param imageCaptchaTrack sliderCaptchaTrack
* @param sliderCaptchaValidData sliderCaptchaValidData
* @param tolerant tolerant
* @param type type
* @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;
}
public boolean doValid(SliderCaptchaTrack sliderCaptchaTrack,
public boolean doValid(ImageCaptchaTrack imageCaptchaTrack,
Map<String, Object> sliderCaptchaValidData,
Float tolerant,
String type) {
if (CaptchaUtils.isSliderCaptcha(type)) {
// 滑动类型验证码
return doValidSliderCaptcha(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
return doValidSliderCaptcha(imageCaptchaTrack, sliderCaptchaValidData, tolerant, 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);
@@ -209,13 +213,13 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
/**
* 校验点选验证码
*
* @param sliderCaptchaTrack sliderCaptchaTrack
* @param imageCaptchaTrack sliderCaptchaTrack
* @param sliderCaptchaValidData sliderCaptchaValidData
* @param tolerant tolerant
* @param type type
* @return boolean
*/
public boolean doValidClickCaptcha(SliderCaptchaTrack sliderCaptchaTrack,
public boolean doValidClickCaptcha(ImageCaptchaTrack imageCaptchaTrack,
Map<String, Object> sliderCaptchaValidData,
Float tolerant,
String type) {
@@ -224,12 +228,12 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
return false;
}
String[] splitArr = validStr.split(";");
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
if (trackList.size() < splitArr.length) {
return false;
}
// 取出点击事件的轨迹数据
List<SliderCaptchaTrack.Track> clickTrackList = trackList
List<ImageCaptchaTrack.Track> clickTrackList = trackList
.stream()
.filter(t -> TrackTypeConstant.CLICK.equalsIgnoreCase(t.getType()))
.collect(Collectors.toList());
@@ -237,14 +241,14 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
return false;
}
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[] posArr = posStr.split(",");
float xPercentage = Float.parseFloat(posArr[0]);
float yPercentage = Float.parseFloat(posArr[1]);
float calcXPercentage = calcPercentage(track.getX(), sliderCaptchaTrack.getBgImageWidth());
float calcYPercentage = calcPercentage(track.getY(), sliderCaptchaTrack.getBgImageHeight());
float calcXPercentage = calcPercentage(track.getX(), imageCaptchaTrack.getBgImageWidth());
float calcYPercentage = calcPercentage(track.getY(), imageCaptchaTrack.getBgImageHeight());
if (!checkPercentage(calcXPercentage, xPercentage, tolerant)
|| !checkPercentage(calcYPercentage, yPercentage, tolerant)) {
@@ -257,13 +261,13 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
/**
* 校验滑动验证码
*
* @param sliderCaptchaTrack sliderCaptchaTrack
* @param imageCaptchaTrack sliderCaptchaTrack
* @param sliderCaptchaValidData sliderCaptchaValidData
* @param tolerant tolerant
* @param type type
* @return boolean
*/
public boolean doValidSliderCaptcha(SliderCaptchaTrack sliderCaptchaTrack,
public boolean doValidSliderCaptcha(ImageCaptchaTrack imageCaptchaTrack,
Map<String, Object> sliderCaptchaValidData,
Float tolerant,
String type) {
@@ -272,11 +276,11 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
// 没读取到百分比
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);
}