pandora-cloud集成 AJ-Captcha行为验证码

1添加背景图片

Q:图片哪里来的?

A:gitee.com/anji-plus/A...

  • jigsaw 滑块拼图底图
  • pic-click 点选文字底图

2 添加依赖

xml 复制代码
<dependencies>
<!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
​
<dependency>
  <groupId>com.anji-plus</groupId>
  <artifactId>captcha-spring-boot-starter</artifactId>
</dependency>
​
​
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
​
​

3 配置验证码集成Redis缓存

  1. 编写RedisCaptchaServiceImpl
typescript 复制代码
package net.ittimeline.pandora.module.system.framework.captcha.core;
​
import com.anji.captcha.service.CaptchaCacheService;
import lombok.Setter;
import org.springframework.data.redis.core.StringRedisTemplate;
​
import java.util.concurrent.TimeUnit;
​
/**
 * 基于 Redis 实现验证码的存储
 * @author tony 18601767221@163.com
 * @version 2025/6/30 13:12
 * @since Java21
 */
@Setter
public class RedisCaptchaServiceImpl implements CaptchaCacheService {
​
    private StringRedisTemplate stringRedisTemplate;
​
​
    @Override
    public void set(String key, String value, long expiresInSeconds) {
        stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
​
    }
​
    @Override
    public boolean exists(String key) {
        return stringRedisTemplate.hasKey(key);
    }
​
    @Override
    public void delete(String key) {
        stringRedisTemplate.delete(key);
    }
​
    @Override
    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }
​
    @Override
    public String type() {
        return "redis";
    }
​
    @Override
    public Long increment(String key, long val) {
        return stringRedisTemplate.opsForValue().increment(key,val);
    }
}
​
  1. 在src/META-INF/services配置net.ittimeline.pandora.aj.captcha.core.RedisCaptchaServiceImpl

4 添加配置

4.1 application.yml

yaml 复制代码
--- #################### 验证码相关配置 ####################
​
aj:
  captcha:
    jigsaw: classpath:images/jigsaw # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径
    pic-click: classpath:images/pic-click # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径
    cache-type: redis # 缓存 local/redis...
    cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存
    timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行
    type: blockPuzzle # 验证码类型 default两种都实例化。 blockPuzzle 滑块拼图 clickWord 文字点选
    water-mark: 潘多拉云平台 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
    interference-options: 0 # 滑动干扰项(0/1/2)
    req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false
    req-get-lock-limit: 5 # 验证失败5次,get接口锁定
    req-get-lock-seconds: 10 # 验证失败后,锁定时间间隔
    req-get-minute-limit: 30 # get 接口一分钟内请求数限制
    req-check-minute-limit: 60 # check 接口一分钟内请求数限制
    req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制
​
​
spring:
  # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
  data:
    redis:
      host: 192.168.3.161 # 地址
      port: 6379 # 端口
      database: 1 # 数据库索引
      password: Guanglei123..go # 密码,建议生产环境开启
server:
  port: 58081
​

4.2 Java配置类

主要配置SpringSecurity、Redis、AJ Captcha

4.2.1 SpringSecurityConfig

java 复制代码
package net.ittimeline.pandora.framework.security.config;
​
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
​
import java.util.Arrays;
​
/**
 * Spring Security 配置
 *
 * @author tony 18601767221@163.com
 * @version 2025/7/2 10:33
 * @since Java21
 */
@AutoConfiguration
public class SpringSecurityConfig {
​
​
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource corsConfigurationSource) throws Exception {
        httpSecurity
                // 允许所有HTTP请求
                .authorizeHttpRequests(requests -> requests.anyRequest().permitAll())
                // 开启跨域
                .cors( (cors) -> { //允许前端跨域访问
                    cors.configurationSource(corsConfigurationSource);
                })
                // CSRF 禁用,因为不使用 Session
                .csrf(AbstractHttpConfigurer::disable)
                // 基于 token 机制,所以不需要 Session
                .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .headers(c -> c.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable));
        // 构建安全链
        return httpSecurity.build();
​
    }
​
​
    @Primary
    @Bean //配置跨域
    public CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
​
        //跨域配置
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(Arrays.asList("*")); //允许任何来源,http://localhost:10492/
        corsConfiguration.setAllowedMethods(Arrays.asList("*")); //允许任何请求方法,post、get、put、delete
        corsConfiguration.setAllowedHeaders(Arrays.asList("*")); //允许任何的请求头 (jwt)
​
        //注册跨域配置
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); //  /api/user,  /api/user/12082
        return urlBasedCorsConfigurationSource;
    }
​
​
    @Bean //配置密码加密器
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
​

SpringSecurityConfig 被定义在 pandora-spring-boot-starter-security 中,因此需要在 org.springframework.boot.autoconfigure.AutoConfiguration.imports 中进行显式声明,以便 Spring Boot 在自动配置阶段能够识别并加载该配置类

4.2.2 PandoraRedisAutoConfiguration

arduino 复制代码
package net.ittimeline.pandora.framework.redis.config;
​
import cn.hutool.core.util.ReflectUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.redisson.spring.starter.RedissonAutoConfigurationV2;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
​
/**
 * Redis 配置类
 *
 * @author tony 18601767221@163.com
 * @version 2025/6/30 13:04
 * @since Java21
 */
@AutoConfiguration(before = RedissonAutoConfigurationV2.class) // 目的:使用自己定义的 RedisTemplate Bean
public class PandoraRedisAutoConfiguration {
    /**
     * 创建 RedisTemplate Bean,使用 JSON 序列化方式
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 创建 RedisTemplate 对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。
        template.setConnectionFactory(factory);
        // 使用 String 序列化方式,序列化 KEY 。
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
        template.setValueSerializer(buildRedisSerializer());
        template.setHashValueSerializer(buildRedisSerializer());
        return template;
    }
​
​
    public static RedisSerializer<?> buildRedisSerializer() {
        RedisSerializer<Object> json = RedisSerializer.json();
        // 解决 LocalDateTime 的序列化
        ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper");
        objectMapper.registerModules(new JavaTimeModule());
        return json;
    }
​
}
​

PandoraRedisAutoConfiguration 被定义在 pandora-spring-boot-starter-redis中,因此需要在 org.springframework.boot.autoconfigure.AutoConfiguration.imports 中进行显式声明,以便 Spring Boot 在自动配置阶段能够识别并加载该配置类

4.2.3 CaptchaConfiguration

kotlin 复制代码
package net.ittimeline.pandora.module.system.framework.captcha.config;
​
import com.anji.captcha.config.AjCaptchaAutoConfiguration;
import com.anji.captcha.properties.AjCaptchaProperties;
import com.anji.captcha.service.CaptchaCacheService;
import com.anji.captcha.service.impl.CaptchaServiceFactory;
import net.ittimeline.pandora.module.system.framework.captcha.core.RedisCaptchaServiceImpl;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.StringRedisTemplate;
​
/**
 * 验证码的配置类
 *
 * @author tony 18601767221@163.com
 * @version 2025/6/30 12:29
 * @since Java21
 */
@Configuration(proxyBeanMethods = false)//
@ImportAutoConfiguration(AjCaptchaAutoConfiguration.class)
public class PandoraCaptchaConfiguration {
​
​
    @Bean(name = "AjCaptchaCacheService")
    @Primary
    public CaptchaCacheService captchaCacheService(AjCaptchaProperties ajCaptchaProperties, StringRedisTemplate stringRedisTemplate) {
        CaptchaCacheService captchaCacheService = CaptchaServiceFactory.getCache(ajCaptchaProperties.getCacheType().name());
        if (captchaCacheService instanceof RedisCaptchaServiceImpl) {
            ((RedisCaptchaServiceImpl) captchaCacheService).setStringRedisTemplate(stringRedisTemplate);
        }
        return captchaCacheService;
    }
}
​

5 编写工具类

typescript 复制代码
package net.ittimeline.pandora.framework.common.util.servlet;
​
import cn.hutool.extra.servlet.JakartaServletUtil;
import jakarta.servlet.http.HttpServletRequest;
​
/**
 * 客户端工具类
 *
 * @author tony 18601767221@163.com
 * @version 2025/7/2 13:11
 * @since Java21
 */
public class ServletUtils {
     /**
     * 获取客户端的IP地址
     *
     * @param request HttpServletRequest对象
     * @return 客户端的IP地址
     */
    public static String getClientIP(HttpServletRequest request) {
        return JakartaServletUtil.getClientIP(request);
    }
​
}
​

6 编写Controller

kotlin 复制代码
package net.ittimeline.pandora.module.system.controller.admin.captcha;
​
import cn.hutool.core.util.StrUtil;
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import net.ittimeline.pandora.framework.common.util.servlet.ServletUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
/**
 * 管理后台-验证码
 *
 * @author tony 18601767221@163.com
 * @version 2025/6/30 12:01
 * @since Java21
 */
@Tag(name = "管理后台-验证码")
@RestController("adminCaptchaController")
@RequestMapping("/admin-api/system/captcha")
public class CaptchaController {
​
    @Resource
    private CaptchaService captchaService;
​
​
    @PostMapping("/get")
    @Operation(summary = "获取验证码")
    public ResponseModel get(@RequestBody CaptchaVO captchaVO, HttpServletRequest request) {
        assert request.getRemoteHost() != null;
        captchaVO.setBrowserInfo(getRemoteId(request));
        return captchaService.get(captchaVO);
    }
​
​
    @PostMapping("/check")
    @Operation(summary = "校验验证码")
    public ResponseModel  check(@RequestBody CaptchaVO captchaVO, HttpServletRequest request) {
        captchaVO.setBrowserInfo(getRemoteId(request));
        return captchaService.check(captchaVO);
    }
​
    /**
     * 该方法用于获取请求的远程标识
     *
     * @param request HttpServletRequest对象,包含客户端请求的信息
     * @return 返回由IP地址和User-Agent组成的字符串,作为远程标识
     */
    public static String getRemoteId(HttpServletRequest request) {
        String ip = ServletUtils.getClientIP(request);
        String ua = request.getHeader("user-agent");
        if (StrUtil.isNotBlank(ip)) {
            return ip + ua;
        }
        return request.getRemoteAddr() + ua;
    }
}
​

7 接口测试

7.1 生成验证码

json 复制代码
{
  "captchaType": "blockPuzzle"
}
  • 响应结果:
json 复制代码
{
    "repCode": "0000",
    "repMsg": null,
    "repData": {
        "captchaId": null,
        "projectCode": null,
        "captchaType": null,
        "captchaOriginalPath": null,
        "captchaFontType": null,
        "captchaFontSize": null,
        "secretKey": "2iq5XHUDJWzgaAoS",
        "originalImageBase64": "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",
        "point": null,
        "jigsawImageBase64": "iVBORw0KGgoAAAANSUhEUgAAAC8AAACbCAYAAADyfMLPAAAFGklEQVR4Xu2YTYhVZRjH7Yts08emRSGEMC1EgzZ9LEIMrRiUDMwaTKm0yY9FKSLVpINKVMwwYZCYMjOFETISmlFDEjWCim0qFy1qdqkR46ZWwUSc5v+O/8Nznvu+59w5M9Pcxf8HD965c6/z+z/vcz7eM2+eEEIIIYQQQgghhBBCCCGEEEIIIYSYOlkC/7mWA5K7ug5m775zOLvSey7769PvQ7V8CIqjDu/vK8j7EP67cwqETp38Ou+673zLBoCIlWZ9+/ZQQfrvgROFAP7/+d+BhJe2Fes+3muJ7lfJ939wKKwAhFF4jeNh7cZ9rSEPQS9Ncf8a47XplZ5QLSMfE/XvU54BWkL+1NH+XNSXXw0bYNblw1+o4Mzxj0KAshA+COWr8D5Ngy9f6n0x1B8Du7Pxkb7s6tmjef15cSh//evZ41MOwfHBwYta0dGVPbxyS/bAox1Z24Or64fAF0Zfb89+7lsX6vKRl7Lx77oK4r4Q4MevBgshUmFiAbz8rYsfy25pe6ie/PmN7aEu7FkdKgQw3ffyXAkEYCFIakWq5CFeW/70+hWhGAArUNV9BsAq2PIrYgPE5BcsfjyI33j3ffXkP1/zSCgGQNnuU3Z89GQoH4D/MkwqALpv5e3I3HzXwnryn61c0hAAK4CD95+LBxrkbfnVsCviA7D7kOfIoPPo+rTkGcCOkO++Fy8LwWPCBsDtAuSferKzIA/xGZVH50e7n2+q+75SASC/77Wu2ZG3ATg6Px3aGZ37srIrYMcHowP5zme3NsjfcPsdMy8//N5b4Y+XyWdjJxresyHQ/WblY3jnHPwyJs/RgTz+cKr7EI/J++7bsbHyPNNAHnXdTdcXqjQE3jy2rK0gb4E8OobuWSErHpO3ATg6deR9iKS8/0D+RjZ5RwkJ3/2UvO+8lbcHbLPy0QDGr3FZrsHfnxn5okGeAbx8WedT8l42VmWeSfClwSOTtwA+QFn3wwVr+MPkqbLZrlv5KQegvO2+XwFflOfZxsvbM02z8gzg/UqhvO9+KoAfGchDfPPO9XMrnzp4y8R5jp8zeW4sOD6pABS3twb2AjWj8uGnijRWngFS44PXfoMyK/J48eai4qXZS4MX3j8WqiA/cRbx8vjX3pChIM6DFffz05Ev+OGHVyfkWR7cwmITQXkGQDd/+LgnGxs+WAhAeT/vdjMya/Lb718UakP78lz8me7+hs7jtgF3nGNDvdm/3wzmOym7o7Ly3MdaeV6gmr1IFcQpj7Epk7dd51NiyuN+HwGalbc7KbuLKus+KYhTPtZ5HFi28yg+AcP8Uv73nskAvvtV8tjDWnkGiOGdc/BLSHcunN8gT1lfQXzXjiDO8t33p0krj9HhBpxPDiBfKhrDyq+7984g3r3qiXBm8NLsOsSxRcQTNsqH8Zk4eK283YR4edv9aT36gDSqe+mSID6wbW2Q9PXJ/h2hKO8DoPsIgFNoVecZgAdubflV99wWxL/c+nQoyKFG9r5cKL4P6d/e2BCKzzjzANfkUZTHNYGnSsjbAHZ8aslDPGz7tjyXC8aK3aY4y64AxsfLs/scPRvAPoCqJY/N9i/bO3K5VOEzKC/PFcBnEMDL8yJlR8ePDwLUkk8Jsav+PYaw37MhcQrF1RcVk08FqCXv5arKyrMK8hMjFpO3o2NDMEAt+arup4R9pbpv5W337QoQ71dJ/s05xDsJIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEGKS/wD3XtEv1IIlhAAAAABJRU5ErkJggg==",
        "wordList": null,
        "pointList": null,
        "pointJson": null,
        "token": "1cf0be8d5606471e98c7d16ee54c7620",
        "result": false,
        "captchaVerification": null,
        "clientUid": null,
        "ts": null,
        "browserInfo": null
    },
    "success": true
}

7.2 验证验证码

json 复制代码
{
  "captchaType": "blockPuzzle",
  "pointJson": "W96Gz51vX97C/6dkuiO0aQ==",
  "token": "db4141243a9049959103c29ff6d6d82a"
}
  • 响应结果
json 复制代码
{
    "repCode": "0000",
    "repMsg": null,
    "repData": {
        "captchaId": null,
        "projectCode": null,
        "captchaType": "blockPuzzle",
        "captchaOriginalPath": null,
        "captchaFontType": null,
        "captchaFontSize": null,
        "secretKey": null,
        "originalImageBase64": null,
        "point": null,
        "jigsawImageBase64": null,
        "wordList": null,
        "pointList": null,
        "pointJson": "W96Gz51vX97C/6dkuiO0aQ==",
        "token": "db4141243a9049959103c29ff6d6d82a",
        "result": true,
        "captchaVerification": null,
        "clientUid": null,
        "ts": null,
        "browserInfo": null
    },
    "success": true
}

8 前端验证

  1. 访问首页:http://localhost/
  1. 点击登录按钮会生成行为验证码
  1. 向右滑动完成验证
相关推荐
Marktowin2 小时前
Mybatis-Plus更新操作时的一个坑
java·后端
赵文宇3 小时前
CNCF Dragonfly 毕业啦!基于P2P的镜像和文件分发系统快速入门,在线体验
后端
程序员爱钓鱼3 小时前
Node.js 编程实战:即时聊天应用 —— WebSocket 实现实时通信
前端·后端·node.js
Libby博仙4 小时前
Spring Boot 条件化注解深度解析
java·spring boot·后端
源代码•宸4 小时前
Golang原理剖析(Map 源码梳理)
经验分享·后端·算法·leetcode·golang·map
小周在成长4 小时前
动态SQL与MyBatis动态SQL最佳实践
后端
瓦尔登湖懒羊羊4 小时前
TCP的自我介绍
后端
小周在成长4 小时前
MyBatis 动态SQL学习
后端
子非鱼9214 小时前
SpringBoot快速上手
java·spring boot·后端
我爱娃哈哈5 小时前
SpringBoot + XXL-JOB + Quartz:任务调度双引擎选型与高可用调度平台搭建
java·spring boot·后端