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

Java Web 驗證碼完整實現代碼分享與原理解析

     編輯:Java 相關知識

在 Web 應用開發中,驗證碼是防止惡意註冊、暴力破解密碼等自動化攻擊的關鍵防線。本文將完整分享一套基於 Java Servlet 的圖形驗證碼實現方案,涵蓋後端生成邏輯、前端展示頁面、驗證邏輯處理及項目結構說明,幫助開發者快速掌握核心技術要點。

一、驗證碼的作用與實現思路

驗證碼的核心目的是區分人類用戶與機器腳本,常見於登入、註冊、表單提交等場景。實現流程主要分三步:

  1. 後端生成:Servlet 隨機生成字母數字組合,繪製干擾線與噪點,輸出 JPEG 圖片流,同時將驗證碼存入 Session。
  2. 前端展示:JSP 頁面通過 <img src="logcheck"> 請求圖片,提供輸入框供用戶填寫。
  3. 驗證比對:用戶提交表單後,Servlet 從 Session 取出原始驗證碼,與用戶輸入進行不區分大小寫比對,返回結果。

二、核心代碼實現

1. 驗證碼生成 Servlet(logcheck.java)

package com;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
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 logcheck extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 設定輸出類型為 JPEG 圖片
        response.setContentType("image/jpeg");
        HttpSession session = request.getSession();

        int width = 60, height = 20;

        // 禁止瀏覽器緩存
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        // 建立內存圖片與畫筆
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();

        // 1. 隨機生成 4 位驗證碼字符
        String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        char[] rands = new char[4];
        for (int i = 0; i < 4; i++) {
            int rand = (int) (Math.random() * 36);
            rands[i] = chars.charAt(rand);
        }

        // 2. 繪製背景
        g.setColor(new Color(0xDCDCDC));
        g.fillRect(0, 0, width, height);

        // 3. 繪製 120 個隨機干擾點
        for (int i = 0; i < 120; i++) {
            int x = (int) (Math.random() * width);
            int y = (int) (Math.random() * height);
            int red = (int) (Math.random() * 255);
            int green = (int) (Math.random() * 255);
            int blue = (int) (Math.random() * 255);
            g.setColor(new Color(red, green, blue));
            g.drawOval(x, y, 1, 0);
        }

        // 4. 繪製驗證碼字符(斜體加粗,錯位排列)
        g.setColor(Color.BLACK);
        g.setFont(new Font(null, Font.ITALIC | Font.BOLD, 18));
        g.drawString(String.valueOf(rands[0]), 1, 17);
        g.drawString(String.valueOf(rands[1]), 16, 15);
        g.drawString(String.valueOf(rands[2]), 31, 18);
        g.drawString(String.valueOf(rands[3]), 46, 16);

        g.dispose();

        // 5. 輸出圖片流
        ServletOutputStream sos = response.getOutputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, "JPEG", baos);
        byte[] buffer = baos.toByteArray();
        response.setContentLength(buffer.length);
        sos.write(buffer);
        baos.close();
        sos.close();

        // 6. 存入 Session 供後續驗證
        session.setAttribute("checkcode", new String(rands));
    }
}

2. 前端展示頁面(index.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<% 
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <base href="<%=basePath%>">
    <title>驗證碼演示頁面</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
</head>
<body>
    <form action="yanzheng" method="post">
        <label>請輸入驗證碼:</label>
        <input type="text" name="name" size="5" maxlength="4" required>
        <a href="index.jsp" title="看不清?點擊刷新">
            <img border="0" src="logcheck" alt="驗證碼圖片" style="vertical-align: middle;">
        </a>
        <br><br>
        <input type="submit" value="提交驗證">
    </form>
</body>
</html>

3. 驗證邏輯 Servlet(yanzheng.java)

package com;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class yanzheng extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String inputCode = request.getParameter("name");
        HttpSession session = request.getSession();
        String sessionCode = (String) session.getAttribute("checkcode");

        String info;
        if (sessionCode != null && sessionCode.equalsIgnoreCase(inputCode)) {
            info = "驗證碼輸入正確";
        } else {
            info = "驗證碼輸入錯誤";
        }

        System.out.println(info);
        request.setAttribute("info", info);
        request.getRequestDispatcher("/login.jsp").forward(request, response);
    }
}

4. 結果展示頁面(login.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<% 
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <base href="<%=basePath%>">
    <title>驗證結果</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
</head>
<body>
    <h3>驗證結果:</h3>
    <p style="color: <%= request.getAttribute("info").toString().contains("正確") ? "green" : "red" %>;">
        <%= request.getAttribute("info") %>
    </p>
    <a href="index.jsp">返回重試</a>
</body>
</html>

三、項目結構與部署說明

將上述 4 個文件放入對應的包結構中:

  • src/com/logcheck.java — 驗證碼生成 Servlet
  • src/com/yanzheng.java — 驗證邏輯 Servlet
  • WebContent/index.jsp — 輸入頁面
  • WebContent/login.jsp — 結果頁面

在 web.xml 中配置 Servlet 映射:

<servlet>
    <servlet-name>logcheck</servlet-name>
    <servlet-class>com.logcheck</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>logcheck</servlet-name>
    <url-pattern>/logcheck</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>yanzheng</servlet-name>
    <servlet-class>com.yanzheng</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>yanzheng</servlet-name>
    <url-pattern>/yanzheng</url-pattern>
</servlet-mapping>

四、進階優化建議

  • 增加干擾線:在繪製字符前後添加 g.drawLine() 繪製隨機直線,提高機器識別難度。
  • 使用更豐富字符集:加入小寫字母、特殊符號,擴大組合空間。
  • 引入成熟庫:生產環境建議使用 EasyCaptcha、Kaptcha 等成熟方案,支援 GIF 動畫、中文、算術題等多種模式。
  • 前端體驗優化:點擊圖片刷新、輸入框自動聚焦、鍵盤 Enter 鍵提交等細節可顯著提升用戶體驗。

本文提供的代碼為教學演示用途,展示了驗證碼的核心實現原理。實際項目中請根據安全等級選擇合適的方案,並注意防止 Session 固定攻擊、驗證碼複用等安全風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved