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

Java 實現隨機驗證碼功能:完整 Servlet 代碼實例詳解

     編輯:Java 相關知識

驗證碼技術原理與應用場景

在現代 Web 應用中,驗證碼是防止惡意註冊、暴力破解、垃圾信息發布的重要防線。其核心原理是:伺服器端生成包含隨機字符的圖片,將字符存入 Session,用戶提交時驗證輸入與 Session 中的值是否一致。為了對抗 OCR 識別,通常會添加干擾線、噪點、字符扭曲等手段增加機器識別難度。

核心實現邏輯

1. 配置參數初始化

通過 web.xml 配置驗證碼圖片的寬度、高度、字符數量等參數,並在 init() 方法中讀取並轉換為整數。

2. 圖片生成核心流程

  1. 創建 BufferedImage 作為畫布
  2. 獲取 Graphics2D 繪圖上下文
  3. 填充背景色(通常為白色)
  4. 設置字體樣式與大小
  5. 繪製邊框
  6. 生成干擾線(示例中生成 160 條)
  7. 隨機選取字符並繪製到圖片上
  8. 將生成的驗證碼字符串存入 HttpSession
  9. 以 JPEG/PNG 格式輸出到響應流

完整 Servlet 實現代碼

package com.servlet;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class ValidateCodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    // 驗證碼圖片寬度
    private int width = 60;
    // 驗證碼圖片高度
    private int height = 20;
    // 驗證碼字符個數
    private int codeCount = 4;
    private int x = 0;
    // 字體高度
    private int fontHeight;
    private int codeY;
    
    // 驗證碼字符集(去除易混淆字符)
    char[] codeSequence = { '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' };

    public void init() throws ServletException {
        // 從 web.xml 讀取初始化參數
        String strWidth = this.getInitParameter("width");
        String strHeight = this.getInitParameter("height");
        String strCodeCount = this.getInitParameter("codeCount");
        
        try {
            if (strWidth != null && strWidth.length() != 0) {
                width = Integer.parseInt(strWidth);
            }
            if (strHeight != null && strHeight.length() != 0) {
                height = Integer.parseInt(strHeight);
            }
            if (strCodeCount != null && strCodeCount.length() != 0) {
                codeCount = Integer.parseInt(strCodeCount);
            }
        } catch (NumberFormatException e) {
            // 使用默認值
        }
        
        x = width / (codeCount + 1);
        fontHeight = height - 2;
        codeY = height - 4;
    }

    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, java.io.IOException {
        
        // 定義圖像緩衝區
        BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = buffImg.createGraphics();
        
        // 創建隨機數生成器
        Random random = new Random();
        
        // 將圖像填充為白色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
        
        // 創建字體
        Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
        g.setFont(font);
        
        // 畫邊框
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, width - 1, height - 1);
        
        // 隨機生成干擾線
        g.setColor(Color.GRAY);
        for (int i = 0; i < 160; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }
        
        // 生成隨機驗證碼字符
        StringBuilder randomCode = new StringBuilder();
        int red, green, blue;
        
        for (int i = 0; i < codeCount; i++) {
            String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
            randomCode.append(strRand);
            
            // 隨機顏色
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);
            g.setColor(new Color(red, green, blue));
            
            g.drawString(strRand, (i + 1) * x, codeY);
        }
        
        // 將驗證碼存入 Session
        HttpSession session = req.getSession(true);
        session.setAttribute("validateCode", randomCode.toString());
        
        // 禁止緩存
        resp.setHeader("Pragma", "no-cache");
        resp.setHeader("Cache-Control", "no-cache");
        resp.setDateHeader("Expires", 0);
        
        // 設置響應類型並輸出圖片
        resp.setContentType("image/jpeg");
        ServletOutputStream sos = resp.getOutputStream();
        ImageIO.write(buffImg, "jpeg", sos);
        sos.close();
    }
}

web.xml 配置示例

<servlet>
    <servlet-name>ValidateCodeServlet</servlet-name>
    <servlet-class>com.servlet.ValidateCodeServlet</servlet-class>
    <init-param>
        <param-name>width</param-name>
        <param-value>120</param-value>
    </init-param>
    <init-param>
        <param-name>height</param-name>
        <param-value>40</param-value>
    </init-param>
    <init-param>
        <param-name>codeCount</param-name>
        <param-value>4</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>ValidateCodeServlet</servlet-name>
    <url-pattern>/validateCode</url-pattern>
</servlet-mapping>

前端調用方式

<img src="validateCode" id="captchaImg" onclick="this.src='validateCode?'+Math.random()" />
<input type="text" name="validateCode" placeholder="請輸入驗證碼" />

安全性增強建議

  • 使用更複雜的字符扭曲算法
  • 添加高斯模糊、噪點等干擾
  • 限制驗證碼有效期(如 60 秒)
  • 驗證失敗後立即使 Session 中的驗證碼失效,防止重放攻擊
  • 考慮使用成熟的驗證碼庫(如 Kaptcha、SimpleCaptcha)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved