Java实现图片验证码具体代码

当网站需要进行用户登录、注册等操作时,为了防止机器人恶意攻击,通常会采用图片验证码的方式来验证用户是否为人类。下面介绍一种基于 Java 实现图片验证码的具体代码,包含验证码生成和校验流程。

生成验证码图片

验证码生成包含以下几个步骤:

  1. 生成随机字符串
/**
 * 生成指定长度的随机字符串
 * @param length 随机字符串长度
 * @return 随机字符串
 */
private static String generateRandomString(int length) {
    StringBuilder sb = new StringBuilder(length);
    for (int i = 0; i < length; i++) {
        int rand = (int) (Math.random() * CHARACTERS.length());
        sb.append(CHARACTERS.charAt(rand));
    }
    return sb.toString();
}

// 可用字符集
private static final String CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  1. 创建图片
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
  1. 绘制字符串
g.setFont(new Font("Arial", Font.BOLD, FONT_SIZE));
for (int i = 0; i < randomString.length(); i++) {
    g.setColor(new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255)));
    g.drawString(String.valueOf(randomString.charAt(i)), i * FONT_SIZE + PADDING_LEFT, FONT_BASELINE_Y);
}
  1. 绘制干扰线和干扰点
for (int i = 0; i < LINE_NUM; i++) {
    g.setColor(new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255)));
    int x1 = (int) (Math.random() * WIDTH);
    int y1 = (int) (Math.random() * HEIGHT);
    int x2 = (int) (Math.random() * WIDTH);
    int y2 = (int) (Math.random() * HEIGHT);
    g.drawLine(x1, y1, x2, y2);
}

for (int i = 0; i < DOT_NUM; i++) {
    g.setColor(new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255)));
    int x = (int) (Math.random() * WIDTH);
    int y = (int) (Math.random() * HEIGHT);
    g.fillOval(x, y, 1, 1);
}
  1. 将图片转为 byte 数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "JPEG", bos);
byte[] imageBytes = bos.toByteArray();
  1. 将随机字符串和图片 byte 数组存入 Redis(可选)

存入 Redis 的目的是方便用户后续的验证码校验,可以将随机字符串作为 key,图片 byte 数组作为 value,设置过期时间,保证验证码的时效性。存入 Redis 示例代码:

String key = "captcha:" + randomString;
redisTemplate.opsForValue().set(key, imageBytes, CAPTCHA_EXPIRE_MILLISECONDS, TimeUnit.MILLISECONDS);

校验验证码

验证码校验包含以下几个步骤:

  1. 获取随机字符串

随机字符串可以从用户提交的表单中获取。

  1. 获取 Redis 中的图片 byte 数组

从 Redis 中获取随机字符串对应的图片 byte 数组,如果获取失败,说明验证码已失效,需要重新生成验证码。

String key = "captcha:" + randomString;
byte[] imageBytes = redisTemplate.opsForValue().get(key);
if (imageBytes == null || imageBytes.length == 0) {
    // 验证码已失效,需要重新生成验证码
    return false;
}
  1. 校验用户提交的验证码和图片中的验证码是否匹配
String userCaptcha = ...; // 用户提交的验证码
String realCaptcha = RecognizeImage.recognize(imageBytes); // 调用图片识别工具获取图片中的验证码
return userCaptcha.equalsIgnoreCase(realCaptcha);

其中,RecognizeImage 是一个图片识别工具类,可以使用 tesseract-ocrjava-ocr 等开源工具实现验证码识别,这里不再赘述。

示例1:Spring Boot 集成 Redis 实现验证码生成和校验

@RestController
@RequestMapping("/captcha")
public class CaptchaController {
    @Resource
    private StringRedisTemplate redisTemplate;

    @GetMapping("/image")
    public ResponseEntity<byte[]> getImageCaptcha(HttpSession session) throws IOException {
        String captcha = generateRandomString(CAPTCHA_LENGTH);
        byte[] imageBytes = generateImageCaptcha(captcha);
        String key = "captcha:image:" + captcha;
        redisTemplate.opsForValue().set(key, captcha, CAPTCHA_EXPIRE_SECONDS, TimeUnit.SECONDS);
        return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(imageBytes);
    }

    @PostMapping("/verify")
    public boolean verifyCaptcha(@RequestParam String captcha, HttpSession session) {
        String key = "captcha:image:" + captcha;
        String realCaptcha = redisTemplate.opsForValue().get(key);
        if (realCaptcha == null) {
            // 验证码已失效
            return false;
        } else {
            // 验证码校验
            redisTemplate.delete(key); // 删除验证码
            return captcha.equalsIgnoreCase(realCaptcha);
        }
    }
}

示例2:使用 Jedis 实现验证码的存取

public class CaptchaUtil {
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    private static final JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), REDIS_HOST, REDIS_PORT);

    // 生成图片验证码并存入 Redis
    public static String generateAndSaveImageCaptcha(int length, int width, int height) throws IOException {
        String captcha = generateRandomString(length);
        byte[] imageBytes = generateImageCaptcha(captcha, width, height);
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.setex(captcha, CAPTCHA_EXPIRE_SECONDS, new String(imageBytes));
        }
        return captcha;
    }

    // 从 Redis 中获取并校验验证码
    public static boolean verifyImageCaptcha(String captcha, String userInput) {
        try (Jedis jedis = jedisPool.getResource()) {
            String realCaptcha = jedis.get(captcha);
            if (realCaptcha == null) {
                // 验证码已失效
                return false;
            } else {
                // 验证码校验
                jedis.del(captcha); // 删除验证码
                String imageString = realCaptcha.substring(1, realCaptcha.length() - 1).replace("\\", "");
                String realUserInput = RecognizeImage.recognize(Base64.getDecoder().decode(imageString));
                return userInput.equalsIgnoreCase(realUserInput);
            }
        }
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java实现图片验证码具体代码 - Python技术站

(0)
上一篇 2023年6月15日
下一篇 2023年6月15日

相关文章

  • java随机字符串生成示例

    当我们需要在Java应用程序中生成随机字符串时,可以使用Java中的Random类来实现。下面是一个完整的Java随机字符串生成示例攻略: 1. 导入Random类 import java.util.Random; 2. 定义随机生成字符串的方法 public static String generateRandomString(int length) { …

    Java 2023年5月26日
    00
  • Java中使用HttpRequest获取用户真实IP地址

    获取用户真实IP地址是Web开发中一个非常重要的问题,这篇文章将详细讲解在Java中使用HttpRequest获取用户真实IP地址的完整攻略。 什么是用户真实IP地址 用户真实IP地址指的是用户连接Internet时获得的IP地址,这个IP地址被称为公网IP地址,因为这个IP地址是在Internet上唯一的,并且可以标识这个用户所在位置的唯一标识。 如何获取…

    Java 2023年6月15日
    00
  • 用3个实例从原理到实战讲清楚Log4j史诗级漏洞

    下面我将通过三个实例,从原理到实战,讲解清楚Log4j史诗级漏洞的完整攻略。 什么是 Log4j Log4j是一个流行的Java日志框架,它是Apache的一个子项目。Log4j可以帮助Java开发人员以更优美的方式记录日志,便于排错和性能调优。 Log4j的漏洞 但是,在2021年底,Log4j被发现有史以来最严重的漏洞,被称为 Log4Shell ,它属…

    Java 2023年6月15日
    00
  • Spring Security配置保姆级教程

    针对“Spring Security配置保姆级教程”的完整攻略,以下是详细的讲解: 前言 Spring Security 是一个基于 Spring 框架的安全模块,为Spring应用提供了声明式的安全访问控制。本文将详细讲解 Spring Security 的配置,帮助初学者掌握 Spring Security 的使用方法。 基本概念 在使用 Spring …

    Java 2023年5月20日
    00
  • Spring Boot 2.0多数据源配置方法实例详解

    Spring Boot 2.0多数据源配置方法实例详解 基础知识 在进行本文的阅读前,读者需要掌握以下知识: Spring Boot 2.0框架基础 数据源的概念和用法 Spring Boot在多数据源方面的优势和实现方式 实现过程 在多数据源的配置中,我们需要主要的是多个数据源的定义和配置。接下来,我们将给出两条实例来帮助读者更好的理解多数据源的配置。 步…

    Java 2023年5月20日
    00
  • 微信小程序实时聊天WebSocket

    下面为您详细讲解“微信小程序实时聊天WebSocket”的完整攻略。 一、前期准备 了解WebSocket协议的基础知识,包括握手过程、消息格式等; 了解微信小程序基础知识,包括小程序开发、页面结构、组件等; 确保开发环境已经安装好,包括微信web开发者工具、编辑器等。 二、创建WebSocket连接 微信小程序提供了wx.connectSocket() A…

    Java 2023年5月23日
    00
  • JavaWeb pageContext对象原理解析

    JavaWeb中,pageContext对象是Servlet容器创建的一个特殊对象,它提供了一些方法来访问Servlet上下文信息和共享数据。在本篇文章中,我们将深入探讨pageContext对象的原理和用法。 什么是pageContext对象 在JSP页面中,我们可以通过EL表达式、JSTL标签等方式来获取Servlet上下文对象、request对象等信息…

    Java 2023年6月15日
    00
  • java解一个比较特殊的数组合并题

    我将为您讲解如何解决一个比较特殊的Java数组合并题。我将分为以下步骤进行讲解: 确定题目要求:根据题目要求,我们需要实现一个方法,用于将两个有序数组合并为一个大的有序数组。 确定解题思路:我们可以使用双指针的方式来解决这个问题,具体思路如下: 1) 我们定义三个指针:p1指向第一个数组的开头,p2指向第二个数组的开头,p3指向新数组的开头。 2) 比较p1…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部