前言

图形验证码是后端开发中最常用的安全校验手段,广泛应用于登录、注册、短信发送等场景。本文基于 SpringBoot3.2.5 快速集成 Kaptcha 生成图形验证码,并将验证码存入 Redis 实现30 秒自动过期,代码简洁、可直接复制运行,完美适配 SpringBoot3 新版本。

一、技术栈

十、总结

本文实现了 SpringBoot3 集成 Kaptcha 图形验证码 + Redis 缓存的完整方案,代码简洁、无冗余、可直接上线使用。核心流程:生成验证码 → Redis 缓存 → 图片输出,是后端登录校验模块的标准实现方案。

  • SpringBoot 3.2.5
  • Kaptcha 2.3.2(图形验证码生成)
  • Redis(验证码缓存 + 自动过期)
  • Java 17
  • Maven
  • 二、Maven 依赖(pom.xml)

    引入 Web、Redis、Kaptcha 核心依赖,SpringBoot3 自动管理版本:

  • <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.2.5</version>
        </parent>
    
        <groupId>com.demo</groupId>
        <artifactId>captcha-demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    
        <properties>
            <java.version>17</java.version>
        </properties>
    
        <dependencies>
            <!-- Web 核心 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- Redis 缓存 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
            </dependency>
    
            <!-- Kaptcha 验证码 -->
            <dependency>
                <groupId>com.github.penggle</groupId>
                <artifactId>kaptcha</artifactId>
                <version>2.3.2</version>
            </dependency>
    
            <!-- Lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

    三、配置文件(application.yml)

    配置 Redis 连接信息,简洁无冗余:

  • server:
      port: 8080
    
    spring:
      # Redis 配置
      redis:
        host: 127.0.0.1
        port: 6379
        password:
        database: 0
        timeout: 10000

    四、Kaptcha 配置类(验证码样式)

    自定义验证码长度、字体、干扰线、尺寸:

    package com.demo.config;
    
    import com.google.code.kaptcha.Producer;
    import com.google.code.kaptcha.impl.DefaultKaptcha;
    import com.google.code.kaptcha.util.Config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Properties;
    
    @Configuration
    public class KaptchaConfig {
    
        @Bean
        public Producer captchaProducer() {
            Properties properties = new Properties();
            // 验证码图片宽度
            properties.setProperty("kaptcha.image.width", "120");
            // 验证码图片高度
            properties.setProperty("kaptcha.image.height", "40");
            // 字体大小
            properties.setProperty("kaptcha.textproducer.font.size", "30");
            // 验证码长度
            properties.setProperty("kaptcha.textproducer.char.length", "4");
            // 字体颜色
            properties.setProperty("kaptcha.textproducer.font.color", "black");
            // 字符范围
            properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    
            Config config = new Config(properties);
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
    }

    五、Redis 配置类(序列化)

    解决 Redis 存储乱码问题:

  • package com.demo.config;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    @Configuration
    public class RedisConfig {
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(factory);
    
            // 序列化配置
            StringRedisSerializer stringSerializer = new StringRedisSerializer();
            Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            jacksonSerializer.setObjectMapper(om);
    
            template.setKeySerializer(stringSerializer);
            template.setValueSerializer(jacksonSerializer);
            template.afterPropertiesSet();
            return template;
        }
    }

    六、工具类(IP 获取 + MD5 加密)

    生成唯一的验证码 Key,防止重复:

  • package com.demo.utils;
    
    import jakarta.servlet.http.HttpServletRequest;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    public class CommonUtil {
    
        /**
         * 获取客户端IP
         */
        public static String getIpAddr(HttpServletRequest request) {
            String ip = request.getHeader("X-Forwarded-For");
            if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }
    
        /**
         * MD5加密生成唯一Key
         */
        public static String md5(String str) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] bytes = md.digest(str.getBytes());
                StringBuilder sb = new StringBuilder();
                for (byte b : bytes) {
                    String hex = Integer.toHexString(b & 0xff);
                    if (hex.length() == 1) sb.append("0");
                    sb.append(hex);
                }
                return sb.toString();
            } catch (NoSuchAlgorithmException e) {
                return null;
            }
        }
    }

    七、验证码 Controller(核心接口)

    生成验证码 → 存入 Redis(30 秒过期) → 返回图片流:

  • package com.demo.controller;
    
    import com.demo.utils.CommonUtil;
    import com.google.code.kaptcha.Producer;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    
    @RestController
    @RequestMapping("/api/auth")
    public class CaptchaController {
    
        @Autowired
        private Producer captchaProducer;
    
        @Autowired
        private RedisTemplate<String, Object> redisTemplate;
    
        /**
         * 获取图形验证码
         */
        @GetMapping("/captcha")
        public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {
            try {
                // 1. 生成验证码文本
                String captchaText = captchaProducer.createText();
                // 2. 生成唯一Key(IP+浏览器标识)
                String key = "captcha:" + CommonUtil.md5(
                        CommonUtil.getIpAddr(request) + request.getHeader("User-Agent")
                );
                // 3. 存入Redis 30秒过期
                redisTemplate.opsForValue().set(key, captchaText, 30, TimeUnit.SECONDS);
    
                // 4. 生成图片
                BufferedImage image = captchaProducer.createImage(captchaText);
                // 5. 设置响应头
                response.setContentType("image/png");
                response.setHeader("Cache-Control", "no-cache");
    
                // 6. 输出图片
                ImageIO.write(image, "png", response.getOutputStream());
                response.getOutputStream().flush();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    八、启动测试

  • 启动本地 Redis 服务
  • 启动 SpringBoot 项目
  • 浏览器访问地址:
  • http://localhost:8080/api/auth/captcha

  • 九、功能说明

  • 验证码生成:Kaptcha 自动生成 4 位字母 + 数字组合验证码
  • 缓存策略:基于用户 IP + 浏览器标识生成唯一 Key,存入 Redis
  • 过期时间:30 秒自动失效,保证安全性
  • SpringBoot3 适配:使用 jakarta.servlet 包,无版本兼容问题
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐