验证码的java代码怎么写

可定义含数字字母的字符池,用Random选指定位数字符拼接成字符串,如`String code = “”; for(int i=0;i

以下是关于 Java实现验证码功能 的完整指南,涵盖原理、代码实现、参数调优及常见问题解答,本文采用模块化叙述方式,结合代码注释与表格对比,帮助您快速掌握核心要点。

验证码的java代码怎么写


验证码基础原理

验证码本质是通过程序动态生成「人眼可识别但机器难以解析」的图形化文本,其核心目标在于区分人类用户与自动化脚本(防爬虫/刷票),典型特征包括:
随机性:每次请求返回不同内容
视觉干扰:背景噪点、干扰线、像素扭曲
字符变形:旋转、缩放、颜色渐变
安全边界:限制尝试次数、绑定Session/Token

特性 作用 实现方式
随机字符串 基础防伪要素 RandomStringUtils工具类
图像渲染 可视化载体 BufferedImage + Graphics2D
干扰元素 破坏机器识别能力 噪声点、折线、弧线
字符扭曲 阻止光学字符识别(OCR) 仿射变换、路径偏移
时效控制 防止重放攻击 存入HttpSession并设置过期时间

完整代码实现(基于Servlet)

核心依赖包

import javax.imageio.ImageIO;
import javax.servlet.http.;
import java.awt.;
import java.awt.image.BufferedImage;
import java.util.Random;

主服务类 CaptchaServlet.java

public class CaptchaServlet extends HttpServlet {
    private static final int WIDTH = 120;      // 图片宽度
    private static final int HEIGHT = 40;      // 图片高度
    private static final String[] CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789"; // 去除非字母数字字符
    private static final int LENGTH = 4;       // 验证码长度
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 创建内存中的图片缓冲区
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        // ======== 第一步:绘制背景 ========
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        // 添加渐变背景增强干扰
        int widthRange = WIDTH / 2;
        for (int i = 0; i < 10; i++) {
            int x = new Random().nextInt(widthRange);
            int y = new Random().nextInt(HEIGHT);
            g.setColor(new Color(200 + i  10, 200 + i  10, 200 + i  10));
            g.drawOval(x, y, 2 + i, 2 + i);
        }
        // ======== 第二步:生成随机字符 ========
        StringBuilder captchaText = new StringBuilder();
        Font font = new Font("Arial", Font.BOLD, 28); // 初始字体大小
        g.setFont(font);
        // 精确计算字符间距
        FontMetrics fm = g.getFontMetrics();
        int charWidth = fm.charWidth('A');
        int totalWidth = (LENGTH 1)  charWidth;
        int startX = (WIDTH totalWidth) / 2;
        for (int i = 0; i < LENGTH; i++) {
            // 随机选择字符
            char c = CHARS[new Random().nextInt(CHARS.length)];
            captchaText.append(c);
            // 设置随机颜色(明度>128保证可读性)
            g.setColor(new Color(
                30 + new Random().nextInt(128),
                30 + new Random().nextInt(128),
                30 + new Random().nextInt(128)
            ));
            // 应用旋转变换(-30°~30°)
            AffineTransform transform = new AffineTransform();
            transform.rotate(Math.toRadians((new Random().nextInt(60) 30)), startX + i  charWidth, HEIGHT/2);
            g.setTransform(transform);
            // 绘制字符(带轻微垂直偏移)
            g.drawString(String.valueOf(c), startX + i  charWidth, HEIGHT/2 + (new Random().nextInt(10) 5));
            g.setTransform(new AffineTransform()); // 重置变换矩阵
        }
        // ======== 第三步:添加干扰元素 ========
        // 绘制干扰线
        for (int i = 0; i < 8; i++) {
            g.setColor(new Color(new Random().nextInt(255), new Random().nextInt(255), new Random().nextInt(255), 150));
            int x1 = new Random().nextInt(WIDTH);
            int y1 = new Random().nextInt(HEIGHT);
            int x2 = new Random().nextInt(WIDTH);
            int y2 = new Random().nextInt(HEIGHT);
            g.drawLine(x1, y1, x2, y2);
        }
        // 添加噪点
        for (int i = 0; i < 50; i++) {
            int x = new Random().nextInt(WIDTH);
            int y = new Random().nextInt(HEIGHT);
            g.setColor(new Color(new Random().nextInt(255), new Random().nextInt(255), new Random().nextInt(255)));
            g.fillRect(x, y, 1, 1);
        }
        // ======== 第四步:保存到Session并输出 ========
        HttpSession session = request.getSession();
        session.setAttribute("CAPTCHA_CODE", captchaText.toString());
        // 设置响应头
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ImageIO.write(image, "jpeg", response.getOutputStream());
    }
}

web.xml配置

<servlet>
    <servlet-name>CaptchaServlet</servlet-name>
    <servlet-class>com.example.CaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>CaptchaServlet</servlet-name>
    <url-pattern>/captcha</url-pattern>
</servlet-mapping>

关键参数详解与调优建议

参数名 默认值 作用说明 调优方向
WIDTH/HEIGHT 120×40 图片尺寸 根据UI设计调整,推荐比例3:1
LENGTH 4 验证码位数 平衡安全性与用户体验
CHARS 排除易混淆字符 可选字符集 可根据业务需求增减特殊符号
干扰线数量 8 影响机器识别难度 5-15条为宜
噪点密度 50 背景噪声强度 30-80个像素点
字体大小 28px 字符清晰度 需配合FontMetrics自动计算
有效期 未显式设置会导致永久有效 应在Session中设置超时时间

最佳实践建议

验证码的java代码怎么写

  1. 双重校验机制:除前端展示外,后端仍需验证提交的验证码是否匹配Session中的值
  2. 频率限制:同一IP短时间内多次失败应触发临时封禁
  3. 多因子认证:高风险操作建议结合短信/邮箱二次验证
  4. 移动端适配:减小图片尺寸至80×30px,增大字符间距

前端调用示例(HTML+JS)

<img id="captchaImg" src="/captcha" onclick="refreshCaptcha()" alt="点击刷新验证码">
<input type="text" id="captchaInput" placeholder="请输入验证码">
<script>
function refreshCaptcha() {
    document.getElementById('captchaImg').src = '/captcha?' + Math.random();
    document.getElementById('captchaInput').value = '';
}
</script>

相关问答FAQs

Q1: 生成的验证码包含中文字符时严重变形怎么办?

A: 中文字符由于笔画复杂,传统仿射变换会导致过度失真,解决方案有两种:

  1. 专用字体方案:使用支持中文且字形稳定的字体文件(如微软雅黑),禁用旋转仅保留平移和缩放
  2. 分段渲染:将每个汉字单独渲染到独立图层,再合并到主画布
    示例修改代码片段:

    // 替换原有字符绘制逻辑
    if (Character.UnicodeScript.of(c) == UnicodeScript.HAN) {
     // 中文字符特殊处理
     g.setFont(new Font("Microsoft YaHei", Font.PLAIN, 24));
     g.drawString(String.valueOf(c), xPos, yPos);
    } else {
     // 英文数字正常处理
     ...
    }

Q2: 如何提升验证码的安全性等级?

A: 可通过以下组合策略增强安全性:
| 安全层级 | 实施措施 | 效果评估 |
|———-|————————————————————————–|——————————|
| 基础级 | 现有实现 + Session绑定 | 防御简单机器人 |
| 中级 | 增加行为轨迹记录(鼠标移动路径) | 拦截普通自动化工具 |
| 高级 | 加入语义理解验证(选出包含汽车的图片) | 有效对抗专业打码平台 |
| 专家级 | 设备指纹识别 + IP信誉库校验 | 精准识别恶意流量来源 |

验证码的java代码怎么写

实际部署时应遵循「最小必要原则」,根据业务风险等级选择合适的安全策略,例如银行系统建议采用「中级+高级」组合,普通论坛使用基础级即可。

原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/102029.html

(0)
酷盾叔的头像酷盾叔
上一篇 2025年8月11日 08:51
下一篇 2025年8月11日 09:02

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-880-8834

在线咨询: QQ交谈

邮件:HI@E.KD.CN