首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 圖形驗證碼生成完整實現(Servlet + JSP + 前端整合)

     編輯:Java 相關知識

核心類:CertPicGenerator

package pic;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;

public class CertPicGenerator {
    // 可用字符集(去除易混淆字符)
    private static final char[] CHAR_SET = {
        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
        '0','1','2','3','4','5','6','7','8','9'
    };
    private static final int DEFAULT_WIDTH = 120;
    private static final int DEFAULT_HEIGHT = 40;
    private static final int CODE_LENGTH = 4;
    private static final int INTERFERE_LINES = 20;
    private static final int INTERFERE_DOTS = 50;

    public String generate(OutputStream os, int width, int height) throws IOException {
        if (width <= 0) width = DEFAULT_WIDTH;
        if (height <= 0) height = DEFAULT_HEIGHT;

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();

        // 背景
        g.setColor(new Color(0xF0F0F0));
        g.fillRect(0, 0, width, height);

        // 邊框
        g.setColor(Color.GRAY);
        g.drawRect(0, 0, width - 1, height - 1);

        // 干擾線
        Random rand = new Random();
        for (int i = 0; i < INTERFERE_LINES; i++) {
            g.setColor(new Color(rand.nextInt(200), rand.nextInt(200), rand.nextInt(200)));
            int x1 = rand.nextInt(width);
            int y1 = rand.nextInt(height);
            int x2 = rand.nextInt(width);
            int y2 = rand.nextInt(height);
            g.drawLine(x1, y1, x2, y2);
        }

        // 干擾點
        for (int i = 0; i < INTERFERE_DOTS; i++) {
            g.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
            g.fillOval(rand.nextInt(width), rand.nextInt(height), 2, 2);
        }

        // 生成驗證碼並繪製
        StringBuilder code = new StringBuilder();
        Font font = new Font("Arial", Font.BOLD | Font.ITALIC, height - 8);
        g.setFont(font);
        int charWidth = (width - 10) / CODE_LENGTH;

        for (int i = 0; i < CODE_LENGTH; i++) {
            char c = CHAR_SET[rand.nextInt(CHAR_SET.length)];
            code.append(c);
            g.setColor(new Color(rand.nextInt(100), rand.nextInt(100), rand.nextInt(100)));
            // 隨機旋轉角度
            double theta = (rand.nextDouble() - 0.5) * 0.6; // -0.3 ~ 0.3 rad
            g.rotate(theta, 10 + i * charWidth + charWidth/2, height/2);
            g.drawString(String.valueOf(c), 10 + i * charWidth, height/2 + 5);
            g.rotate(-theta, 10 + i * charWidth + charWidth/2, height/2);
        }

        g.dispose();
        ImageIO.write(image, "JPEG", os);
        return code.toString();
    }
}

JSP 端點:captcha.jsp

<%@ page contentType="image/jpeg" import="pic.CertPicGenerator" %>
<%
    CertPicGenerator gen = new CertPicGenerator();
    String code = gen.generate(response.getOutputStream(), 0, 0);
    session.setAttribute("captchaCode", code); // 存入 Session
    response.getOutputStream().flush();
%>

登入頁面整合:login.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>登入</title>
<script>
function refreshCaptcha() {
    var img = document.getElementById('captchaImg');
    img.src = 'captcha.jsp?t=' + Math.random(); // 防快取
}
</script>
</head>
<body>
<form action="loginCheck.jsp" method="post">
    用戶名:<input type="text" name="username" /><br/>
    密碼:<input type="password" name="password" /><br/>
    驗證碼:
    <img id="captchaImg" src="captcha.jsp" onclick="refreshCaptcha()" alt="點擊換一張" style="cursor:pointer; vertical-align:middle;" />
    <input type="text" name="captchaInput" size="6" /><br/>
    <input type="submit" value="登入" />
</form>
</body>
</html>

後端驗證:loginCheck.jsp

<%
    String input = request.getParameter("captchaInput");
    String real = (String) session.getAttribute("captchaCode");
    if (real != null && real.equalsIgnoreCase(input)) {
        out.println("驗證碼正確,繼續登入邏輯...");
        // 登入成功後清除驗證碼
        session.removeAttribute("captchaCode");
    } else {
        out.println("驗證碼錯誤,請重試。<a href='login.jsp'>返回</a>");
    }
%>

關鍵增強點

  1. 字符集優化:移除 0/O, 1/I, 2/Z 等易混淆字符。
  2. 干擾線+干擾點+隨機旋轉+隨機顏色:大幅提高機器識別難度。
  3. Session 存儲:驗證碼僅保存在 Session,不暴露於前端。
  4. 點擊刷新:前端加時間戳防止瀏覽器快取。
  5. 忽略大小寫驗證:提升用戶體驗。

生產環境建議

  • 使用成熟庫(如 kaptcha, simple-captcha)替代手寫實現。
  • 考慮滑塊、點選、行為分析等更友好的驗證方式。
  • 加入請求頻率限制,防止暴力破解驗證碼接口。
  • 驗證碼圖片響應頭設定 Cache-Control: no-store。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved