diff --git a/continew-starter-captcha/continew-starter-captcha-behavior/pom.xml b/continew-starter-captcha/continew-starter-captcha-behavior/pom.xml
new file mode 100644
index 00000000..879b8f0b
--- /dev/null
+++ b/continew-starter-captcha/continew-starter-captcha-behavior/pom.xml
@@ -0,0 +1,31 @@
+
+
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.starter.captcha.behavior.autoconfigure;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+import com.anji.captcha.model.common.Const;
+import com.anji.captcha.service.CaptchaService;
+import com.anji.captcha.service.impl.CaptchaServiceFactory;
+import com.anji.captcha.util.ImageUtils;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * 行为验证码自动配置
+ *
+ * @author Bull-BCLS
+ * @since 1.1.0
+ */
+@Slf4j
+@AutoConfiguration
+@RequiredArgsConstructor
+@ConditionalOnProperty(prefix = "continew-starter.captcha.behavior", name = "enabled", havingValue = "true")
+@EnableConfigurationProperties(BehaviorCaptchaProperties.class)
+public class BehaviorCaptchaAutoConfiguration {
+
+ private final BehaviorCaptchaProperties properties;
+
+ /**
+ * 自定义缓存实现配置
+ */
+ @Configuration
+ @Import({BehaviorCaptchaCacheConfiguration.Redis.class, BehaviorCaptchaCacheConfiguration.Local.class, BehaviorCaptchaCacheConfiguration.Custom.class})
+ protected static class BehaviorCaptchaCacheAutoConfiguration {
+ }
+
+ /**
+ * 行为验证码服务接口
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public CaptchaService captchaService() {
+ Properties config = new Properties();
+ config.put(Const.CAPTCHA_CACHETYPE, properties.getCacheType().name().toLowerCase());
+ config.put(Const.CAPTCHA_WATER_MARK, properties.getWaterMark());
+ config.put(Const.CAPTCHA_FONT_TYPE, properties.getFontType());
+ config.put(Const.CAPTCHA_TYPE, properties.getType().getCodeValue());
+ config.put(Const.CAPTCHA_INTERFERENCE_OPTIONS, properties.getInterferenceOptions());
+ config.put(Const.ORIGINAL_PATH_JIGSAW, StrUtil.emptyIfNull(properties.getJigsawBaseMapPath()));
+ config.put(Const.ORIGINAL_PATH_PIC_CLICK, StrUtil.emptyIfNull(properties.getPicClickBaseMapPath()));
+ config.put(Const.CAPTCHA_SLIP_OFFSET, properties.getSlipOffset());
+ config.put(Const.CAPTCHA_AES_STATUS, String.valueOf(properties.getEnableAES()));
+ config.put(Const.CAPTCHA_WATER_FONT, properties.getWaterFont());
+ config.put(Const.CAPTCHA_CACAHE_MAX_NUMBER, properties.getCacheNumber());
+ config.put(Const.CAPTCHA_TIMING_CLEAR_SECOND, properties.getTimingClear());
+ config.put(Const.HISTORY_DATA_CLEAR_ENABLE, properties.getHistoryDataClearEnable());
+ config.put(Const.REQ_FREQUENCY_LIMIT_ENABLE, properties.getReqFrequencyLimitEnable());
+ config.put(Const.REQ_GET_LOCK_LIMIT, properties.getReqGetLockLimit());
+ config.put(Const.REQ_GET_LOCK_SECONDS, properties.getReqGetLockSeconds());
+ config.put(Const.REQ_GET_MINUTE_LIMIT, properties.getReqGetMinuteLimit());
+ config.put(Const.REQ_CHECK_MINUTE_LIMIT, properties.getReqCheckMinuteLimit());
+ config.put(Const.REQ_VALIDATE_MINUTE_LIMIT, properties.getReqVerifyMinuteLimit());
+ config.put(Const.CAPTCHA_FONT_SIZE, properties.getFontSize());
+ config.put(Const.CAPTCHA_FONT_STYLE, properties.getFontStyle());
+ config.put(Const.CAPTCHA_WORD_COUNT, 4);
+ if (StrUtil.startWith(properties.getJigsawBaseMapPath(), "classpath:")
+ || StrUtil.startWith(properties.getPicClickBaseMapPath(), "classpath:")) {
+ // 自定义 resources 目录下初始化底图
+ config.put(Const.CAPTCHA_INIT_ORIGINAL, true);
+ initializeBaseMap(properties.getJigsawBaseMapPath(), properties.getPicClickBaseMapPath());
+ }
+ return CaptchaServiceFactory.getInstance(config);
+ }
+
+ /**
+ * 初始化 行为/点选 验证码底图
+ *
+ * @param jigsaw 行为验证码底图路径
+ * @param picClick 点选验证码底图路径
+ */
+ private static void initializeBaseMap(String jigsaw, String picClick) {
+ ImageUtils.cacheBootImage(getResourcesImagesFile(jigsaw + "/original/*.png"),
+ getResourcesImagesFile(jigsaw + "/slidingBlock/*.png"),
+ getResourcesImagesFile(picClick + "/*.png"));
+ }
+
+ /**
+ * 获取图片
+ *
+ * @param path 图片路径
+ * @return key:图片文件名称;value:图片
+ */
+ private static Map
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.starter.captcha.behavior.autoconfigure;
+
+import cn.hutool.core.util.ReflectUtil;
+import com.anji.captcha.service.CaptchaCacheService;
+import com.anji.captcha.service.impl.CaptchaCacheServiceMemImpl;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.client.RedisClient;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import top.charles7c.continew.starter.cache.redisson.autoconfigure.RedissonAutoConfiguration;
+import top.charles7c.continew.starter.captcha.behavior.impl.BehaviorCaptchaCacheServiceImpl;
+
+/**
+ * 行为验证码缓存配置
+ *
+ * @author Bull-BCLS
+ * @since 1.1.0
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+abstract class BehaviorCaptchaCacheConfiguration {
+
+ /**
+ * 自定义缓存实现类-Redis
+ */
+ @ConditionalOnClass(RedisClient.class)
+ @ConditionalOnMissingBean(CaptchaCacheService.class)
+ @AutoConfigureBefore(RedissonAutoConfiguration.class)
+ @ConditionalOnProperty(name = "continew-starter.captcha.behavior.cache-type", havingValue = "redis")
+ static class Redis {
+ static {
+ log.debug("[ContiNew Starter] - Auto Configuration 'Behavior-CaptchaCache-Redis' completed initialization.");
+ }
+
+ @Bean
+ public CaptchaCacheService captchaCacheService() {
+ return new BehaviorCaptchaCacheServiceImpl();
+ }
+ }
+
+ /**
+ * 自定义缓存实现类-内存
+ */
+ @ConditionalOnMissingBean(CaptchaCacheService.class)
+ @ConditionalOnProperty(name = "continew-starter.captcha.behavior.cache-type", havingValue = "local")
+ static class Local {
+ static {
+ log.debug("[ContiNew Starter] - Auto Configuration 'Behavior-CaptchaCache-Local' completed initialization.");
+ }
+
+ @Bean
+ public CaptchaCacheService captchaCacheService() {
+ return new CaptchaCacheServiceMemImpl();
+ }
+ }
+
+ /**
+ * 自定义缓存实现类-自定义
+ */
+ @ConditionalOnMissingBean(CaptchaCacheService.class)
+ @ConditionalOnProperty(name = "continew-starter.captcha.behavior.cache-type", havingValue = "custom")
+ static class Custom {
+ static {
+ log.debug("[ContiNew Starter] - Auto Configuration 'Behavior-CaptchaCache-Custom' completed initialization.");
+ }
+
+ @Bean
+ public CaptchaCacheService captchaCacheService(BehaviorCaptchaProperties properties) {
+ return ReflectUtil.newInstance(properties.getCacheImpl());
+ }
+ }
+}
diff --git a/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/autoconfigure/BehaviorCaptchaProperties.java b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/autoconfigure/BehaviorCaptchaProperties.java
new file mode 100644
index 00000000..eb9239b3
--- /dev/null
+++ b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/autoconfigure/BehaviorCaptchaProperties.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.starter.captcha.behavior.autoconfigure;
+
+import com.anji.captcha.model.common.CaptchaTypeEnum;
+import com.anji.captcha.service.CaptchaCacheService;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import top.charles7c.continew.starter.captcha.behavior.enums.StorageType;
+
+import java.awt.*;
+
+/**
+ * 行为验证码配置属性
+ *
+ * @author Bull-BCLS
+ * @since 1.1.0
+ */
+@Data
+@ConfigurationProperties(prefix = "continew-starter.captcha.behavior")
+public class BehaviorCaptchaProperties {
+
+ /**
+ * 是否启用行为验证码
+ */
+ private boolean enabled = false;
+
+ /**
+ * 是否开启 AES 坐标加密(默认:true)
+ */
+ private Boolean enableAES = true;
+
+ /**
+ * 验证码类型(默认:滑动验证码)
+ */
+ private CaptchaTypeEnum type = CaptchaTypeEnum.BLOCKPUZZLE;
+
+ /**
+ * 缓存类型(默认:LOCAL 内存)
+ */
+ private StorageType cacheType = StorageType.LOCAL;
+
+ /**
+ * 自定义缓存类型(当 cacheType 为 CUSTOM 时必填)
+ */
+ private Class extends CaptchaCacheService> cacheImpl;
+
+ /**
+ * 滑动拼图底图路径(为空则使用默认底图)(路径下需要有两个文件夹,分别为 original(存放底图)slidingBlock(存放滑块))
+ */
+ private String jigsawBaseMapPath;
+
+ /**
+ * 校验滑动拼图允许误差偏移量(默认:5像素)
+ */
+ private String slipOffset = "5";
+
+ /**
+ * 点选文字底图路径(为空则使用默认底图)
+ */
+ private String picClickBaseMapPath;
+
+ /**
+ * 点选文字验证码的文字字体(默认:文泉驿正黑)
+ */
+ private String fontType = "WenQuanZhengHei.ttf";
+
+ /**
+ * 历史数据清除开关(0:关闭;1:开启)
+ */
+ private Integer historyDataClearEnable = 0;
+
+ /**
+ * 一分钟内接口请求次数限制开关(0:关闭;1:开启)
+ */
+ private Integer reqFrequencyLimitEnable = 0;
+
+ /**
+ * 一分钟内验证码最多失败次数限制(默认:5次)
+ */
+ private int reqGetLockLimit = 5;
+
+ /**
+ * 一分钟内验证码最多失败次数限制达标后锁定时间(默认:300秒)
+ */
+ private int reqGetLockSeconds = 300;
+
+ /**
+ * 获取验证码接口一分钟内请求次数限制(默认:100次)
+ */
+ private int reqGetMinuteLimit = 100;
+
+ /**
+ * 校验检验码接口一分内请求次数限制(默认:100次)
+ */
+ private int reqCheckMinuteLimit = 100;
+
+ /**
+ * 二次校验检验码接口一分钟内请求次数限制(默认:100次)
+ */
+ private int reqVerifyMinuteLimit = 100;
+
+ /**
+ * local缓存的阈值(默认:1000个)
+ */
+ private String cacheNumber = "1000";
+
+ /**
+ * 定时清理过期local缓存(默认:180秒)
+ */
+ private String timingClear = "180";
+
+ /**
+ * 右下角水印文字
+ */
+ private String waterMark = "我的水印";
+
+ /**
+ * 右下角水印字体(默认:文泉驿正黑)
+ */
+ private String waterFont = "WenQuanZhengHei.ttf";
+
+ /**
+ * 滑块干扰项(默认:0)
+ */
+ private String interferenceOptions = "0";
+
+ /**
+ * 点选字体样式(默认:BOLD)
+ */
+ private int fontStyle = Font.BOLD;
+
+ /**
+ * 点选字体大小(默认:25)
+ */
+ private int fontSize = 25;
+}
diff --git a/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/enums/StorageType.java b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/enums/StorageType.java
new file mode 100644
index 00000000..b711488d
--- /dev/null
+++ b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/enums/StorageType.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.starter.captcha.behavior.enums;
+
+import lombok.Getter;
+
+/**
+ * 缓存类型枚举
+ *
+ * @author Bull-BCLS
+ * @since 1.1.0
+ */
+@Getter
+public enum StorageType {
+
+ /**
+ * 内存
+ */
+ LOCAL,
+
+ /**
+ * Redis
+ */
+ REDIS,
+
+ /**
+ * 自定义
+ */
+ CUSTOM,
+}
diff --git a/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/impl/BehaviorCaptchaCacheServiceImpl.java b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/impl/BehaviorCaptchaCacheServiceImpl.java
new file mode 100644
index 00000000..980ed591
--- /dev/null
+++ b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/java/top/charles7c/continew/starter/captcha/behavior/impl/BehaviorCaptchaCacheServiceImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.charles7c.continew.starter.captcha.behavior.impl;
+
+import com.anji.captcha.service.CaptchaCacheService;
+import top.charles7c.continew.starter.cache.redisson.util.RedisUtils;
+import top.charles7c.continew.starter.captcha.behavior.enums.StorageType;
+
+import java.time.Duration;
+
+/**
+ * 行为验证码 Redis 缓存实现
+ *
+ * @author Bull-BCLS
+ * @since 1.1.0
+ */
+public class BehaviorCaptchaCacheServiceImpl implements CaptchaCacheService {
+ @Override
+ public void set(String key, String value, long expiresInSeconds) {
+ RedisUtils.set(key, value, Duration.ofSeconds(expiresInSeconds));
+ }
+
+ @Override
+ public boolean exists(String key) {
+ return RedisUtils.hasKey(key);
+ }
+
+ @Override
+ public void delete(String key) {
+ RedisUtils.delete(key);
+ }
+
+ @Override
+ public String get(String key) {
+ return RedisUtils.get(key);
+ }
+
+ @Override
+ public String type() {
+ return StorageType.REDIS.name().toLowerCase();
+ }
+}
diff --git a/continew-starter-captcha/continew-starter-captcha-behavior/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000..64298ebd
--- /dev/null
+++ b/continew-starter-captcha/continew-starter-captcha-behavior/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+top.charles7c.continew.starter.captcha.behavior.autoconfigure.BehaviorCaptchaAutoConfiguration
\ No newline at end of file
diff --git a/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/autoconfigure/GraphicCaptchaProperties.java b/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/autoconfigure/GraphicCaptchaProperties.java
index 4e4abd08..fd17ce1a 100644
--- a/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/autoconfigure/GraphicCaptchaProperties.java
+++ b/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/autoconfigure/GraphicCaptchaProperties.java
@@ -21,7 +21,7 @@ import cn.hutool.core.util.StrUtil;
import com.wf.captcha.base.Captcha;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
-import top.charles7c.continew.starter.captcha.graphic.enums.GraphicCaptchaTypeEnum;
+import top.charles7c.continew.starter.captcha.graphic.enums.GraphicCaptchaType;
import java.awt.*;
@@ -43,7 +43,7 @@ public class GraphicCaptchaProperties {
/**
* 类型
*/
- private GraphicCaptchaTypeEnum type;
+ private GraphicCaptchaType type;
/**
* 内容长度
diff --git a/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/enums/GraphicCaptchaTypeEnum.java b/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/enums/GraphicCaptchaType.java
similarity index 97%
rename from continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/enums/GraphicCaptchaTypeEnum.java
rename to continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/enums/GraphicCaptchaType.java
index 4eb227ae..506992c7 100644
--- a/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/enums/GraphicCaptchaTypeEnum.java
+++ b/continew-starter-captcha/continew-starter-captcha-graphic/src/main/java/top/charles7c/continew/starter/captcha/graphic/enums/GraphicCaptchaType.java
@@ -29,7 +29,7 @@ import lombok.RequiredArgsConstructor;
*/
@Getter
@RequiredArgsConstructor
-public enum GraphicCaptchaTypeEnum {
+public enum GraphicCaptchaType {
/**
* 算术
diff --git a/continew-starter-captcha/pom.xml b/continew-starter-captcha/pom.xml
index 49357f8f..842c2cc6 100644
--- a/continew-starter-captcha/pom.xml
+++ b/continew-starter-captcha/pom.xml
@@ -17,6 +17,7 @@