🧩 技术选型

  • Spring Boot

  • Hutool(用于生成图形验证码)

  • ConcurrentHashMap(用于本地缓存)

  • 可选扩展:定时清理过期验证码


📦 引入依赖(Maven)

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Hutool 工具包 -->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.23</version>
    </dependency>
</dependencies>

🧠 本地缓存验证码管理类

package com.example.demo.util;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;

public class CaptchaCache {
    private static final Map<String, CaptchaItem> CACHE = new ConcurrentHashMap<>();
    private static final long EXPIRE_TIME = 3 * 60 * 1000L; // 3分钟有效期

    // 存储验证码
    public static String put(String code) {
        String uuid = UUID.randomUUID().toString();
        CACHE.put(uuid, new CaptchaItem(code, System.currentTimeMillis()));
        return uuid;
    }

    // 获取验证码并校验是否过期
    public static String get(String uuid) {
        CaptchaItem item = CACHE.get(uuid);
        if (item == null || System.currentTimeMillis() - item.timestamp > EXPIRE_TIME) {
            CACHE.remove(uuid);
            return null;
        }
        return item.code;
    }

    public static void remove(String uuid) {
        CACHE.remove(uuid);
    }

    // 内部类:验证码对象
    private static class CaptchaItem {
        String code;
        long timestamp;

        CaptchaItem(String code, long timestamp) {
            this.code = code;
            this.timestamp = timestamp;
        }
    }
}

📸 验证码生成接口

package com.example.demo.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.example.demo.util.CaptchaCache;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
@RequestMapping("/captcha")
public class CaptchaController {

    // 生成验证码图片
    @GetMapping("/generate")
    public void generateCaptcha(HttpServletResponse response) throws IOException {
        // 创建验证码图片对象
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(160, 60, 4, 20);

        // 保存验证码到缓存中
        String uuid = CaptchaCache.put(lineCaptcha.getCode());

        // 设置返回头
        response.setHeader("Captcha-UUID", uuid);
        response.setContentType("image/png");

        // 输出图片流
        ImageIO.write(lineCaptcha.getImage(), "png", response.getOutputStream());
    }

    // 校验验证码
    @PostMapping("/verify")
    public String verifyCaptcha(@RequestParam String uuid, @RequestParam String code) {
        String cachedCode = CaptchaCache.get(uuid);
        if (cachedCode == null) {
            return "验证码已过期或不存在";
        }

        if (cachedCode.equalsIgnoreCase(code)) {
            CaptchaCache.remove(uuid); // 一次性使用
            return "验证码正确";
        } else {
            return "验证码错误";
        }
    }
}

🔁 可选:定时清理缓存任务(使用 Spring 定时任务)

package com.example.demo.config;

import com.example.demo.util.CaptchaCache;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class CaptchaCleanupTask {

    // 每5分钟清理一次(可选)
    @Scheduled(fixedRate = 5 * 60 * 1000)
    public void cleanExpiredCaptcha() {
        // 如果你想实现,可以修改 CaptchaCache 结构并实现遍历清理过期项
        // 示例中未实现遍历清理,建议使用 Guava Cache 或 caffeine 更优雅
    }
}

✅ 使用说明

  1. 前端调用 GET /captcha/generate 接口,拿到图片和响应头中的 Captcha-UUID

  2. 用户输入验证码后,提交 POST /captcha/verify?uuid=xxx&code=xxx

  3. 后端校验并返回验证结果


🔒 提示

  • 本地缓存适用于单体应用或小型项目,如果分布式部署,建议用 Redis。

  • Hutool 生成的是干扰线图形验证码,也可用 CircleCaptchaShearCaptcha 替代。

Logo

网易易盾是国内领先的数字内容风控服务商,依托网易二十余年的先进技术和一线实践经验沉淀,为客户提供专业可靠的安全服务,涵盖内容安全、业务安全、应用安全、安全专家服务四大领域,全方位保障客户业务合规、稳健和安全运营。

更多推荐