mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
feat(captcha): 升级验证码校验流程与资源管理
- 引入MatchParam封装滑动轨迹及相关信息,提升扩展性。- 调整验证码生成与校验接口,以支持更精细的参数控制。 - 优化资源管理,提高验证码资源的加载效率。 - 更新文档与示例代码,以反映API的最新变化。BREAKING CHANGE: 验证码校验接口发生改变,现在需要传入MatchParam对象而非直接传入轨迹对象。这可能会影响直接调用验证码校验服务的客户端代码,需根据最新API文档进行适配。
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>cloud.tianai.captcha</groupId>
|
<groupId>cloud.tianai.captcha</groupId>
|
||||||
<artifactId>tianai-captcha</artifactId>
|
<artifactId>tianai-captcha</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.1</version>
|
||||||
|
|
||||||
<name>tianai-captcha</name>
|
<name>tianai-captcha</name>
|
||||||
<description>行为验证码</description>
|
<description>行为验证码</description>
|
||||||
|
|||||||
@@ -37,13 +37,15 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cloud.tianai.captcha</groupId>
|
<groupId>cloud.tianai.captcha</groupId>
|
||||||
<artifactId>tianai-captcha</artifactId>
|
<artifactId>tianai-captcha</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 构建 `ImageCaptchaApplication`负责生成和校验验证码
|
### 2. 构建 `ImageCaptchaApplication`负责生成和校验验证码
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
|
|
||||||
public class ApplicationTest {
|
public class ApplicationTest {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@@ -63,7 +65,7 @@ public class ApplicationTest {
|
|||||||
// 注意: 该项目只负责生成和校验验证码数据, 至于二次验证等需要自行扩展
|
// 注意: 该项目只负责生成和校验验证码数据, 至于二次验证等需要自行扩展
|
||||||
String id = res.getId();
|
String id = res.getId();
|
||||||
ImageCaptchaTrack imageCaptchaTrack = null;
|
ImageCaptchaTrack imageCaptchaTrack = null;
|
||||||
ApiResponse<?> valid = application.matching(id, imageCaptchaTrack);
|
ApiResponse<?> valid = application.matching(id, new MatchParam(imageCaptchaTrack));
|
||||||
System.out.println(valid.isSuccess());
|
System.out.println(valid.isSuccess());
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import cloud.tianai.captcha.interceptor.EmptyCaptchaInterceptor;
|
|||||||
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
||||||
import cloud.tianai.captcha.validator.ImageCaptchaValidator;
|
import cloud.tianai.captcha.validator.ImageCaptchaValidator;
|
||||||
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
import cloud.tianai.captcha.validator.impl.SimpleImageCaptchaValidator;
|
import cloud.tianai.captcha.validator.impl.SimpleImageCaptchaValidator;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -155,23 +156,28 @@ public class DefaultImageCaptchaApplication implements ImageCaptchaApplication {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<?> matching(String id, ImageCaptchaTrack imageCaptchaTrack) {
|
public ApiResponse<?> matching(String id, MatchParam matchParam) {
|
||||||
AnyMap validData = getVerification(id);
|
AnyMap validData = getVerification(id);
|
||||||
if (validData == null) {
|
if (validData == null) {
|
||||||
return ApiResponse.ofMessage(ApiResponseStatusConstant.EXPIRED);
|
return ApiResponse.ofMessage(ApiResponseStatusConstant.EXPIRED);
|
||||||
}
|
}
|
||||||
ApiResponse<?> response = beforeValid(id, imageCaptchaTrack, validData);
|
ApiResponse<?> response = beforeValid(id, matchParam, validData);
|
||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
ApiResponse<?> basicValid = getImageCaptchaValidator().valid(imageCaptchaTrack, validData);
|
ApiResponse<?> basicValid = getImageCaptchaValidator().valid(matchParam.getTrack(), validData);
|
||||||
response = afterValid(id, imageCaptchaTrack, validData, basicValid);
|
response = afterValid(id, matchParam, validData, basicValid);
|
||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
return basicValid;
|
return basicValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiResponse<?> matching(String id, ImageCaptchaTrack track) {
|
||||||
|
return matching(id, new MatchParam(track, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matching(String id, Float percentage) {
|
public boolean matching(String id, Float percentage) {
|
||||||
@@ -295,12 +301,12 @@ public class DefaultImageCaptchaApplication implements ImageCaptchaApplication {
|
|||||||
captchaInterceptor.afterGenerateImageCaptchaValidData(captchaInterceptor.createContext(), imageCaptchaInfo.getType(), imageCaptchaInfo, validData);
|
captchaInterceptor.afterGenerateImageCaptchaValidData(captchaInterceptor.createContext(), imageCaptchaInfo.getType(), imageCaptchaInfo, validData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApiResponse<?> beforeValid(String id, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData) {
|
private ApiResponse<?> beforeValid(String id, MatchParam matchParam, AnyMap validData) {
|
||||||
return captchaInterceptor.beforeValid(captchaInterceptor.createContext(), getCaptchaTypeById(id), imageCaptchaTrack, validData);
|
return captchaInterceptor.beforeValid(captchaInterceptor.createContext(), getCaptchaTypeById(id), matchParam, validData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApiResponse<?> afterValid(String id, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData, ApiResponse<?> basicValid) {
|
private ApiResponse<?> afterValid(String id, MatchParam matchParam, AnyMap validData, ApiResponse<?> basicValid) {
|
||||||
return captchaInterceptor.afterValid(captchaInterceptor.createContext(), getCaptchaTypeById(id), imageCaptchaTrack, validData, basicValid);
|
return captchaInterceptor.afterValid(captchaInterceptor.createContext(), getCaptchaTypeById(id), matchParam, validData, basicValid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import cloud.tianai.captcha.interceptor.CaptchaInterceptor;
|
|||||||
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
||||||
import cloud.tianai.captcha.validator.ImageCaptchaValidator;
|
import cloud.tianai.captcha.validator.ImageCaptchaValidator;
|
||||||
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
@@ -51,8 +52,13 @@ public class FilterImageCaptchaApplication implements ImageCaptchaApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<?> matching(String id, ImageCaptchaTrack ImageCaptchaTrack) {
|
public ApiResponse<?> matching(String id, MatchParam matchParam) {
|
||||||
return target.matching(id, ImageCaptchaTrack);
|
return target.matching(id, matchParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiResponse<?> matching(String id, ImageCaptchaTrack track) {
|
||||||
|
return target.matching(id, track);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import cloud.tianai.captcha.interceptor.CaptchaInterceptor;
|
|||||||
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
||||||
import cloud.tianai.captcha.validator.ImageCaptchaValidator;
|
import cloud.tianai.captcha.validator.ImageCaptchaValidator;
|
||||||
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
@@ -64,13 +65,22 @@ public interface ImageCaptchaApplication {
|
|||||||
* 匹配
|
* 匹配
|
||||||
*
|
*
|
||||||
* @param id 验证码的ID
|
* @param id 验证码的ID
|
||||||
* @param imageCaptchaTrack 滑动轨迹
|
* @param matchParam 匹配数据,包含鼠标轨迹,设备信息等
|
||||||
* @return 匹配成功返回true, 否则返回false
|
* @return 匹配成功返回true, 否则返回false
|
||||||
*/
|
*/
|
||||||
ApiResponse<?> matching(String id, ImageCaptchaTrack imageCaptchaTrack);
|
ApiResponse<?> matching(String id, MatchParam matchParam);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 兼容一下旧版本,新版本建议使用 {@link ImageCaptchaApplication#matching(String, ImageCaptchaTrack)}
|
* 兼容一下旧版本,新版本建议使用 {@link ImageCaptchaApplication#matching(String, MatchParam)}
|
||||||
|
*
|
||||||
|
* @param id 验证码的ID
|
||||||
|
* @param track 轨迹数据
|
||||||
|
* @return 匹配成功返回true, 否则返回false
|
||||||
|
*/
|
||||||
|
ApiResponse<?> matching(String id, ImageCaptchaTrack track);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容一下旧版本,新版本建议使用 {@link ImageCaptchaApplication#matching(String, MatchParam)}
|
||||||
*
|
*
|
||||||
* @param id id
|
* @param id id
|
||||||
* @param percentage 百分比数据
|
* @param percentage 百分比数据
|
||||||
@@ -114,6 +124,7 @@ public interface ImageCaptchaApplication {
|
|||||||
* @return CaptchaInterceptor
|
* @return CaptchaInterceptor
|
||||||
*/
|
*/
|
||||||
CaptchaInterceptor getCaptchaInterceptor();
|
CaptchaInterceptor getCaptchaInterceptor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置 拦截器
|
* 设置 拦截器
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package cloud.tianai.captcha.common;
|
package cloud.tianai.captcha.common;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -8,6 +10,7 @@ import java.util.function.BiConsumer;
|
|||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@EqualsAndHashCode
|
||||||
public class AnyMap implements Map<String, Object> {
|
public class AnyMap implements Map<String, Object> {
|
||||||
|
|
||||||
private Map<String, Object> target;
|
private Map<String, Object> target;
|
||||||
@@ -19,6 +22,7 @@ public class AnyMap implements Map<String, Object> {
|
|||||||
public AnyMap(Map<String, Object> map) {
|
public AnyMap(Map<String, Object> map) {
|
||||||
this.target = map;
|
this.target = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Float getFloat(String key) {
|
public Float getFloat(String key) {
|
||||||
return getFloat(key, null);
|
return getFloat(key, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package cloud.tianai.captcha.common.exception;
|
|||||||
* @Description 图片验证码异常
|
* @Description 图片验证码异常
|
||||||
*/
|
*/
|
||||||
public class ImageCaptchaException extends RuntimeException{
|
public class ImageCaptchaException extends RuntimeException{
|
||||||
|
|
||||||
public ImageCaptchaException() {
|
public ImageCaptchaException() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,5 +24,4 @@ public class ImageCaptchaException extends RuntimeException {
|
|||||||
public ImageCaptchaException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
public ImageCaptchaException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ public class ApiResponse<T> implements Serializable {
|
|||||||
public static final ApiResponse<?> SUCCESS;
|
public static final ApiResponse<?> SUCCESS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
//默认
|
|
||||||
CodeDefinition definition = ApiResponseStatusConstant.SUCCESS;
|
CodeDefinition definition = ApiResponseStatusConstant.SUCCESS;
|
||||||
SUCCESS = new ApiResponse(definition.getCode(), definition.getMessage(), null);
|
SUCCESS = new ApiResponse(definition.getCode(), definition.getMessage(), null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,24 +15,12 @@ public interface ApiResponseStatusConstant {
|
|||||||
*/
|
*/
|
||||||
CodeDefinition SUCCESS = new CodeDefinition(200, "OK");
|
CodeDefinition SUCCESS = new CodeDefinition(200, "OK");
|
||||||
|
|
||||||
/**
|
|
||||||
* 无效参数
|
|
||||||
*/
|
|
||||||
CodeDefinition NOT_VALID_PARAM = new CodeDefinition(403, "无效参数");
|
CodeDefinition NOT_VALID_PARAM = new CodeDefinition(403, "无效参数");
|
||||||
|
|
||||||
/**
|
|
||||||
* 未知的内部错误
|
|
||||||
*/
|
|
||||||
CodeDefinition INTERNAL_SERVER_ERROR = new CodeDefinition(500, "未知的内部错误");
|
CodeDefinition INTERNAL_SERVER_ERROR = new CodeDefinition(500, "未知的内部错误");
|
||||||
|
|
||||||
/**
|
|
||||||
* 已失效
|
|
||||||
*/
|
|
||||||
CodeDefinition EXPIRED = new CodeDefinition(4000, "已失效");
|
CodeDefinition EXPIRED = new CodeDefinition(4000, "已失效");
|
||||||
|
|
||||||
/**
|
|
||||||
* 基础校验失败
|
|
||||||
*/
|
|
||||||
CodeDefinition BASIC_CHECK_FAIL = new CodeDefinition(4001, "基础校验失败");
|
CodeDefinition BASIC_CHECK_FAIL = new CodeDefinition(4001, "基础校验失败");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import lombok.*;
|
|||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@EqualsAndHashCode
|
// param作为扩展字段暂时将param从equals和toString中移除掉 以适应 CacheImageCaptchaGenerator
|
||||||
|
@EqualsAndHashCode(exclude = "param")
|
||||||
public class GenerateParam {
|
public class GenerateParam {
|
||||||
|
|
||||||
|
|
||||||
@@ -60,4 +61,5 @@ public class GenerateParam {
|
|||||||
}
|
}
|
||||||
return param.getOrDefault(key, defaultValue);
|
return param.getOrDefault(key, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
|
|||||||
rotateImageCaptchaInfo.setRandomX(randomX);
|
rotateImageCaptchaInfo.setRandomX(randomX);
|
||||||
rotateImageCaptchaInfo.setBackgroundImage(backgroundImage);
|
rotateImageCaptchaInfo.setBackgroundImage(backgroundImage);
|
||||||
rotateImageCaptchaInfo.setBackgroundImageTag(backgroundImageTag);
|
rotateImageCaptchaInfo.setBackgroundImageTag(backgroundImageTag);
|
||||||
rotateImageCaptchaInfo.setTemplateImage(templateImageTag);
|
rotateImageCaptchaInfo.setTemplateImageTag(templateImageTag);
|
||||||
rotateImageCaptchaInfo.setTolerant(DEFAULT_TOLERANT);
|
rotateImageCaptchaInfo.setTolerant(DEFAULT_TOLERANT);
|
||||||
rotateImageCaptchaInfo.setTemplateImage(templateImage);
|
rotateImageCaptchaInfo.setTemplateImage(templateImage);
|
||||||
rotateImageCaptchaInfo.setBackgroundImageWidth(bgImageWidth);
|
rotateImageCaptchaInfo.setBackgroundImageWidth(bgImageWidth);
|
||||||
|
|||||||
@@ -211,4 +211,5 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
|
|||||||
public void setInterceptor(CaptchaInterceptor interceptor) {
|
public void setInterceptor(CaptchaInterceptor interceptor) {
|
||||||
target.setInterceptor(interceptor);
|
target.setInterceptor(interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import cloud.tianai.captcha.generator.AbstractImageCaptchaGenerator;
|
|||||||
import cloud.tianai.captcha.generator.common.model.dto.CaptchaExchange;
|
import cloud.tianai.captcha.generator.common.model.dto.CaptchaExchange;
|
||||||
import cloud.tianai.captcha.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
|
|
||||||
// ============================ 拦截器执行顺序 ============================
|
// ============================ 拦截器执行顺序 ============================
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ public interface CaptchaInterceptor {
|
|||||||
default void afterGenerateCaptcha(Context context, String type, ImageCaptchaInfo imageCaptchaInfo, CaptchaResponse<ImageCaptchaVO> captchaResponse) {
|
default void afterGenerateCaptcha(Context context, String type, ImageCaptchaInfo imageCaptchaInfo, CaptchaResponse<ImageCaptchaVO> captchaResponse) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default ApiResponse<?> beforeValid(Context context, String type, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData) {
|
default ApiResponse<?> beforeValid(Context context, String type, MatchParam matchParam, AnyMap validData) {
|
||||||
Object preReturn = context.getPreReturnData();
|
Object preReturn = context.getPreReturnData();
|
||||||
if (preReturn != null) {
|
if (preReturn != null) {
|
||||||
return (ApiResponse<?>) preReturn;
|
return (ApiResponse<?>) preReturn;
|
||||||
@@ -63,7 +63,7 @@ public interface CaptchaInterceptor {
|
|||||||
return ApiResponse.ofSuccess();
|
return ApiResponse.ofSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
default ApiResponse<?> afterValid(Context context, String type, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData, ApiResponse<?> basicValid) {
|
default ApiResponse<?> afterValid(Context context, String type, MatchParam matchParam, AnyMap validData, ApiResponse<?> basicValid) {
|
||||||
Object preReturn = context.getPreReturnData();
|
Object preReturn = context.getPreReturnData();
|
||||||
if (preReturn != null) {
|
if (preReturn != null) {
|
||||||
return (ApiResponse<?>) preReturn;
|
return (ApiResponse<?>) preReturn;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import cloud.tianai.captcha.generator.AbstractImageCaptchaGenerator;
|
|||||||
import cloud.tianai.captcha.generator.common.model.dto.CaptchaExchange;
|
import cloud.tianai.captcha.generator.common.model.dto.CaptchaExchange;
|
||||||
import cloud.tianai.captcha.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.generator.common.model.dto.ImageCaptchaInfo;
|
import cloud.tianai.captcha.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -87,24 +87,24 @@ public class CaptchaInterceptorGroup implements CaptchaInterceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<?> beforeValid(Context context, String type, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData) {
|
public ApiResponse<?> beforeValid(Context context, String type, MatchParam matchParam, AnyMap validData) {
|
||||||
context = createContextIfNecessary(context);
|
context = createContextIfNecessary(context);
|
||||||
ApiResponse<?> beforeValid = null;
|
ApiResponse<?> beforeValid = null;
|
||||||
while (context.next() < context.getCount()) {
|
while (context.next() < context.getCount()) {
|
||||||
CaptchaInterceptor interceptor = validators.get(context.getCurrent());
|
CaptchaInterceptor interceptor = validators.get(context.getCurrent());
|
||||||
beforeValid = interceptor.beforeValid(context, type, imageCaptchaTrack, validData);
|
beforeValid = interceptor.beforeValid(context, type, matchParam, validData);
|
||||||
context.setPreReturnData(beforeValid);
|
context.setPreReturnData(beforeValid);
|
||||||
}
|
}
|
||||||
return beforeValid == null ? ApiResponse.ofSuccess() : beforeValid;
|
return beforeValid == null ? ApiResponse.ofSuccess() : beforeValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<?> afterValid(Context context, String type, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData, ApiResponse<?> basicValid) {
|
public ApiResponse<?> afterValid(Context context, String type, MatchParam matchParam, AnyMap validData, ApiResponse<?> basicValid) {
|
||||||
context = createContextIfNecessary(context);
|
context = createContextIfNecessary(context);
|
||||||
ApiResponse<?> valid = null;
|
ApiResponse<?> valid = null;
|
||||||
while (context.next() < context.getCount()) {
|
while (context.next() < context.getCount()) {
|
||||||
CaptchaInterceptor interceptor = validators.get(context.getCurrent());
|
CaptchaInterceptor interceptor = validators.get(context.getCurrent());
|
||||||
valid = interceptor.afterValid(context, type, imageCaptchaTrack, validData, basicValid);
|
valid = interceptor.afterValid(context, type, matchParam, validData, basicValid);
|
||||||
context.setPreReturnData(valid);
|
context.setPreReturnData(valid);
|
||||||
}
|
}
|
||||||
return valid == null ? ApiResponse.ofSuccess() : valid;
|
return valid == null ? ApiResponse.ofSuccess() : valid;
|
||||||
|
|||||||
+4
-2
@@ -7,6 +7,7 @@ import cloud.tianai.captcha.common.util.CaptchaTypeClassifier;
|
|||||||
import cloud.tianai.captcha.interceptor.CaptchaInterceptor;
|
import cloud.tianai.captcha.interceptor.CaptchaInterceptor;
|
||||||
import cloud.tianai.captcha.interceptor.Context;
|
import cloud.tianai.captcha.interceptor.Context;
|
||||||
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -24,14 +25,15 @@ public class BasicTrackCaptchaInterceptor implements CaptchaInterceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<?> afterValid(Context context, String type, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData, ApiResponse<?> basicValid) {
|
public ApiResponse<?> afterValid(Context context, String type, MatchParam matchData, AnyMap validData, ApiResponse<?> basicValid) {
|
||||||
if (!basicValid.isSuccess()) {
|
if (!basicValid.isSuccess()) {
|
||||||
return context.getGroup().afterValid(context, type, imageCaptchaTrack, validData, basicValid);
|
return context.getGroup().afterValid(context, type, matchData, validData, basicValid);
|
||||||
}
|
}
|
||||||
if (!CaptchaTypeClassifier.isSliderCaptcha(type)) {
|
if (!CaptchaTypeClassifier.isSliderCaptcha(type)) {
|
||||||
// 不是滑动验证码的话暂时跳过,点选验证码行为轨迹还没做
|
// 不是滑动验证码的话暂时跳过,点选验证码行为轨迹还没做
|
||||||
return ApiResponse.ofSuccess();
|
return ApiResponse.ofSuccess();
|
||||||
}
|
}
|
||||||
|
ImageCaptchaTrack imageCaptchaTrack = matchData.getTrack();
|
||||||
// 进行行为轨迹检测
|
// 进行行为轨迹检测
|
||||||
long startSlidingTime = imageCaptchaTrack.getStartTime().getTime();
|
long startSlidingTime = imageCaptchaTrack.getStartTime().getTime();
|
||||||
long endSlidingTime = imageCaptchaTrack.getStopTime().getTime();
|
long endSlidingTime = imageCaptchaTrack.getStopTime().getTime();
|
||||||
|
|||||||
+3
-2
@@ -7,6 +7,7 @@ import cloud.tianai.captcha.common.util.ObjectUtils;
|
|||||||
import cloud.tianai.captcha.interceptor.CaptchaInterceptor;
|
import cloud.tianai.captcha.interceptor.CaptchaInterceptor;
|
||||||
import cloud.tianai.captcha.interceptor.Context;
|
import cloud.tianai.captcha.interceptor.Context;
|
||||||
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
||||||
|
import cloud.tianai.captcha.validator.common.model.dto.MatchParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
@@ -15,8 +16,8 @@ import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;
|
|||||||
*/
|
*/
|
||||||
public class ParamCheckCaptchaInterceptor implements CaptchaInterceptor {
|
public class ParamCheckCaptchaInterceptor implements CaptchaInterceptor {
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<?> beforeValid(Context context, String type, ImageCaptchaTrack imageCaptchaTrack, AnyMap validData) {
|
public ApiResponse<?> beforeValid(Context context, String type, MatchParam matchParam, AnyMap validData) {
|
||||||
checkParam(imageCaptchaTrack);
|
checkParam(matchParam.getTrack());
|
||||||
return ApiResponse.ofSuccess();
|
return ApiResponse.ofSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import java.io.InputStream;
|
|||||||
* @Description 抽象的ResourceProvider
|
* @Description 抽象的ResourceProvider
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractResourceProvider implements ResourceProvider {
|
public abstract class AbstractResourceProvider implements ResourceProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream getResourceInputStream(Resource data) {
|
public InputStream getResourceInputStream(Resource data) {
|
||||||
InputStream resourceInputStream = doGetResourceInputStream(data);
|
InputStream resourceInputStream = doGetResourceInputStream(data);
|
||||||
@@ -27,5 +26,4 @@ public abstract class AbstractResourceProvider implements ResourceProvider {
|
|||||||
* @return InputStream
|
* @return InputStream
|
||||||
*/
|
*/
|
||||||
public abstract InputStream doGetResourceInputStream(Resource data);
|
public abstract InputStream doGetResourceInputStream(Resource data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||||||
* @Description 默认的资源存储
|
* @Description 默认的资源存储
|
||||||
*/
|
*/
|
||||||
public class LocalMemoryResourceStore implements ResourceStore {
|
public class LocalMemoryResourceStore implements ResourceStore {
|
||||||
|
|
||||||
private static final String TYPE_TAG_SPLIT_FLAG = "|";
|
private static final String TYPE_TAG_SPLIT_FLAG = "|";
|
||||||
|
|
||||||
/** 用于检索 type和tag. */
|
/** 用于检索 type和tag. */
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package cloud.tianai.captcha.validator.common.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Drives {
|
||||||
|
private Integer hardwareConcurrency;
|
||||||
|
private Boolean hasXhr = false;
|
||||||
|
private String href;
|
||||||
|
private String language;
|
||||||
|
private Long start;
|
||||||
|
private Long now;
|
||||||
|
private String platform;
|
||||||
|
private Integer scripts;
|
||||||
|
private String userAgent;
|
||||||
|
private Integer windowHeight;
|
||||||
|
private Integer windowWidth;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package cloud.tianai.captcha.validator.common.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2024/8/19 15:12
|
||||||
|
* @Description 验证码匹配的对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class MatchParam {
|
||||||
|
/** 轨迹信息. */
|
||||||
|
private ImageCaptchaTrack track;
|
||||||
|
/** 检测到的设备信息. */
|
||||||
|
private Drives drives;
|
||||||
|
/** 留一个扩展属性. */
|
||||||
|
private Object extendData;
|
||||||
|
|
||||||
|
|
||||||
|
public MatchParam(ImageCaptchaTrack track) {
|
||||||
|
this.track = track;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MatchParam(ImageCaptchaTrack track, Drives drives) {
|
||||||
|
this.track = track;
|
||||||
|
this.drives = drives;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,7 +16,6 @@ import java.util.List;
|
|||||||
* @Description 基本的行为轨迹校验
|
* @Description 基本的行为轨迹校验
|
||||||
*/
|
*/
|
||||||
public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
||||||
|
|
||||||
public static final CodeDefinition DEFINITION = new CodeDefinition(50001, "basic check fail");
|
public static final CodeDefinition DEFINITION = new CodeDefinition(50001, "basic check fail");
|
||||||
|
|
||||||
public BasicCaptchaTrackValidator() {
|
public BasicCaptchaTrackValidator() {
|
||||||
|
|||||||
Reference in New Issue
Block a user