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

Java 生成驗證碼完整實現:圖片干擾、字體扭曲、Session 綁定、Spring MVC 整合

     編輯:Java 相關知識

驗證碼核心需求

  • **機器不可識別**:干擾線、噪點、字體扭曲、顏色隨機
  • **人類可識別**:字符清晰、對比度高、尺寸適中
  • **一次性使用**:生成 → Session 存儲 → 驗證即銷毀
  • **高性能**:無磁盤 I/O,直接輸出流

核心工具類:VerifyCodeUtils


public class VerifyCodeUtils {
    
    // 字符集:去除易混淆 0/O、1/I/l、2/Z、8/B 等
    private static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
    private static final Random RANDOM = new Random();
    
    // 1. 生成隨機字符串
    public static String generateVerifyCode(int length) {
        return generateVerifyCode(length, VERIFY_CODES);
    }
    
    public static String generateVerifyCode(int length, String sources) {
        if (sources == null || sources.isEmpty()) sources = VERIFY_CODES;
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(sources.charAt(RANDOM.nextInt(sources.length())));
        }
        return sb.toString();
    }
    
    // 2. 輸出圖片到 OutputStream (核心方法)
    public static void outputImage(int width, int height, OutputStream os, String code) 
            throws IOException {
        
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = image.createGraphics();
        
        // 抗鋸齒
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        // 隨機背景色
        Color[] colors = randomColors(5);
        float[] fractions = randomFractions(5);
        Arrays.sort(fractions);
        
        // 邊框
        g2.setColor(Color.GRAY);
        g2.fillRect(0, 0, width, height);
        
        // 背景漸變
        Color bg = getRandomColor(200, 255);
        g2.setColor(bg);
        g2.fillRect(0, 2, width, height - 4);
        
        // 3. 干擾線
        g2.setColor(getRandomColor(50, 255));
        for (int i = 0; i < 20; i++) {
            int x = RANDOM.nextInt(width - 1);
            int y = RANDOM.nextInt(height - 1);
            int xl = RANDOM.nextInt(6) + 1;
            int yl = RANDOM.nextInt(12) + 1;
            g2.drawLine(x, y, x + xl + 40, y + yl + 20);
        }
        
        // 4. 噪點
        float yawpRate = 0.05f;
        int area = (int) (yawpRate * width * height);
        for (int i = 0; i < area; i++) {
            int x = RANDOM.nextInt(width);
            int y = RANDOM.nextInt(height);
            image.setRGB(x, y, getRandomIntColor());
        }
        
        // 5. 扭曲變換 (核心反識別)
        shear(g2, width, height, bg);
        
        // 6. 繪制字符
        int fontSize = height - 4;
        Font font = new Font("Algerian", Font.ITALIC, fontSize); // 需系統安裝
        g2.setFont(font);
        char[] chars = code.toCharArray();
        
        for (int i = 0; i < chars.length; i++) {
            AffineTransform affine = new AffineTransform();
            // 隨機旋轉 ±45°
            double angle = Math.PI / 4 * RANDOM.nextDouble() * (RANDOM.nextBoolean() ? 1 : -1);
            affine.setToRotation(angle, 
                (width / chars.length) * i + fontSize / 2, height / 2);
            g2.setTransform(affine);
            
            g2.setColor(getRandomColor(100, 160));
            g2.drawChars(chars, i, 1, 
                ((width - 10) / chars.length) * i + 5, 
                height - (height - (int)(fontSize * 0.75)) / 2);
        }
        
        g2.dispose();
        ImageIO.write(image, "jpg", os);
    }
    
    // 輔助方法:隨機顏色、剪切變換等 (見完整代碼)
    private static Color getRandomColor(int fc, int bc) { /* ... */ }
    private static int getRandomIntColor() { /* ... */ }
    private static void shear(Graphics g, int w, int h, Color color) { /* ... */ }
    private static void shearX(Graphics g, int w, int h, Color color) { /* ... */ }
    private static void shearY(Graphics g, int w, int h, Color color) { /* ... */ }
}

關鍵反識別技術解析

技術實現效果
字符集過濾移除 0/O、1/I/l、2/Z、5/S、8/B、U/V消除視覺歧義
隨機字體Algerian 等藝術字體 + 斜體破壞標準字符特徵
仿射變換`AffineTransform` 隨機旋轉 ±45°字符傾斜、位移,OCR 難分割
剪切扭曲`shearX/shearY` 正弦波形平移整體圖像波浪扭曲,連通域破壞
干擾線隨機顏色、位置、長度直線干擾字符邊緣檢測
噪點5% 密度隨機像素增加背景複雜度
顏色隨機字符、背景、干擾線顏色均隨機無固定顏色特徵可利用

Spring MVC Controller 整合


@Controller
public class VerifyCodeController {
    
    @GetMapping("/verifyCode")
    public void verifyCode(HttpServletRequest request, HttpServletResponse response) 
            throws IOException {
        
        // 1. 禁用緩存
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        
        // 2. 生成驗證碼
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        
        // 3. 存入 Session (轉小寫不區分大小寫)
        HttpSession session = request.getSession(true);
        session.setAttribute("verifyCode", verifyCode.toLowerCase());
        
        // 4. 輸出圖片流
        VerifyCodeUtils.outputImage(200, 80, response.getOutputStream(), verifyCode);
    }
}

前端使用


<img id="verifyCodeImg" src="/verifyCode" alt="點擊刷新" 
     onclick="this.src='/verifyCode?t=' + Date.now()" style="cursor:pointer;" />
<input type="text" name="verifyCode" placeholder="請輸入驗證碼" />

驗證邏輯 (登錄/表單提交)


@PostMapping("/login")
public Result login(@RequestParam String username, 
                    @RequestParam String password,
                    @RequestParam String verifyCode,
                    HttpSession session) {
    
    String savedCode = (String) session.getAttribute("verifyCode");
    if (savedCode == null || !savedCode.equalsIgnoreCase(verifyCode)) {
        return Result.error("驗證碼錯誤或已過期");
    }
    
    // 驗證通過,立即移除防止重用
    session.removeAttribute("verifyCode");
    
    // 後續業務邏輯...
    return Result.success();
}

生產環境優化建議

  1. 字體備選:系統無 Algerian 時回退 `Arial`、`Verdana`,或項目打包 `.ttf` 字體文件動態加載
  2. 性能優化:`BufferedImage` 對象池化、異步生成、CDN 緩存靜態資源
  3. 安全加固:驗證碼加密存儲 (AES)、限制驗證次數 (防暴力)、圖片加水印標識來源
  4. 無障礙支持:提供語音驗證碼選項、高對比度模式
  5. 現代替代:行為驗證 (滑塊、點選)、設備指紋、風控引擎 (Google reCAPTCHA v3、阿里云驗證碼)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved