验证码作为一种常见的安全机制,主要用于防止恶意注册、暴力破解等自动化攻击,在Java Web开发中,实现验证码功能通常涉及生成随机字符串、绘制验证码图片、前端展示及用户输入验证等步骤,本文将详细介绍Java实现验证码的核心流程与代码示例。

验证码的基本概念
验证码(CAPTCHA)的全称是“全自动区分计算机和人类的公开图灵测试”,其核心目的是通过用户输入的随机字符串,判断操作者是否为真实用户,常见的验证码类型包括字符验证码、滑块验证码、点选验证码等,其中字符验证码因实现简单、兼容性好而被广泛应用。
实现步骤详解
生成随机验证码字符串
验证码的第一步是生成随机字符串,通常包含数字、字母(避免易混淆的字符如0/o、1/l等),长度一般为4-6位,Java中可通过Random类和字符池实现:
import java.util.Random;
public class CaptchaUtil {
private static final char[] CHAR_POOL =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
public static String generateCaptcha(int length) {
StringBuilder captcha = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
captcha.append(CHAR_POOL[random.nextInt(CHAR_POOL.length)]);
}
return captcha.toString();
}
}
绘制验证码图片
生成字符串后,需将其绘制为图片,并添加干扰元素(如干扰线、干扰点、噪点)增加识别难度,核心是使用BufferedImage和Graphics2D类:

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
public class CaptchaImageUtil {
public static void generateImage(String captcha, OutputStream out) throws IOException {
int width = 120, height = 40;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
// 设置背景色
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
// 设置字体
g2d.setFont(new Font("Arial", Font.BOLD, 24));
// 绘制验证码字符
for (int i = 0; i < captcha.length(); i++) {
int x = 20 + i * 20;
int y = 25 + (int)(Math.random() * 10);
double angle = Math.random() * 0.4 - 0.2; // 随机旋转角度
g2d.rotate(angle, x, y);
g2d.setColor(new Color(
(int)(Math.random() * 128),
(int)(Math.random() * 128),
(int)(Math.random() * 128)
));
g2d.drawString(String.valueOf(captcha.charAt(i)), x, y);
g2d.rotate(-angle, x, y); // 重置旋转角度
}
// 绘制干扰线
g2d.setStroke(new BasicStroke(1.5f));
for (int i = 0; i < 5; i++) {
g2d.setColor(new Color(
(int)(Math.random() * 256),
(int)(Math.random() * 256),
(int)(Math.random() * 256)
));
int x1 = (int)(Math.random() * width);
int y1 = (int)(Math.random() * height);
int x2 = (int)(Math.random() * width);
int y2 = (int)(Math.random() * height);
g2d.drawLine(x1, y1, x2, y2);
}
// 绘制干扰点
for (int i = 0; i < 30; i++) {
g2d.setColor(new Color(
(int)(Math.random() * 256),
(int)(Math.random() * 256),
(int)(Math.random() * 256)
));
int x = (int)(Math.random() * width);
int y = (int)(Math.random() * height);
g2d.fillOval(x, y, 2, 2);
}
g2d.dispose();
ImageIO.write(image, "JPEG", out);
}
}
后端接口实现
在Spring Boot等框架中,可通过接口将生成的验证码图片返回给前端,并将验证码字符串存入Session(或Redis)以便后续验证:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@RestController
public class CaptchaController {
@GetMapping("/captcha")
public void getCaptcha(HttpSession session, HttpServletResponse response) throws IOException {
String captcha = CaptchaUtil.generateCaptcha(4);
session.setAttribute("captcha", captcha); // 存入Session
response.setContentType("image/jpeg");
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.setHeader("Pragma", "no-cache");
CaptchaImageUtil.generateImage(captcha, response.getOutputStream());
}
}
前端展示与验证
前端通过img标签展示验证码图片,点击图片可刷新验证码,用户提交输入后,后端从Session中取出验证码进行比对(忽略大小写):
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@RestController
public class ValidateController {
@PostMapping("/validate")
public String validateCaptcha(
@RequestParam String userInput,
HttpSession session) {
String captcha = (String) session.getAttribute("captcha");
if (captcha == null) {
return "验证码已过期,请重新获取";
}
if (captcha.equalsIgnoreCase(userInput)) {
session.removeAttribute("captcha"); // 验证成功后清除Session
return "验证成功";
} else {
return "验证码错误";
}
}
}
常见问题与优化
- 验证码过期时间:可通过Session设置过期时间(如
session.setMaxInactiveInterval(60 * 1000),1分钟过期)。 - 干扰元素优化:干扰线数量、颜色随机性可调整,避免过于复杂影响用户体验。
- 字符复杂度:可增加小写字母或特殊字符(如排除易混淆的
O、0等)。 - 前端刷新机制:通过点击图片重新调用
/captcha接口,并添加时间戳防止缓存(如src="/captcha?t=" + new Date().getTime())。 - 防止暴力破解:可限制用户验证失败次数,超过次数后锁定账号或延长验证码刷新间隔。
通过以上步骤,即可在Java项目中实现一个功能完善的字符验证码,实际开发中,可根据需求调整验证码样式、存储方式(如改用Redis)及安全策略,以平衡安全性与用户体验。














