最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Boot使用Hutool快速集成驗(yàn)證碼的兩種方案

 更新時(shí)間:2026年02月10日 09:13:23   作者:???傀儡師  
驗(yàn)證碼作為一種簡(jiǎn)單而有效的身份驗(yàn)證手段,被廣泛應(yīng)用于各種在線服務(wù)中,這篇文章主要介紹了Spring?Boot使用Hutool快速集成驗(yàn)證碼的兩種方案,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

驗(yàn)證碼這件“小事”,其實(shí)一點(diǎn)也不小

在登錄、注冊(cè)、找回密碼這些看似普通的業(yè)務(wù)場(chǎng)景里,驗(yàn)證碼往往是系統(tǒng)安全的第一道防線。如果沒(méi)有它,爬蟲(chóng)、撞庫(kù)腳本、暴力請(qǐng)求可以輕松把你的接口打穿;但如果驗(yàn)證碼實(shí)現(xiàn)得不好,又會(huì)帶來(lái)代碼冗余、維護(hù)困難、樣式僵硬等一系列工程問(wèn)題。

很多項(xiàng)目都會(huì)經(jīng)歷這樣一個(gè)過(guò)程:

  • 一開(kāi)始:“不就是個(gè)驗(yàn)證碼嗎?我自己畫(huà)!”
  • 后來(lái):干擾線、字體、隨機(jī)數(shù)、Session、緩存控制……越寫(xiě)越多
  • 最終:發(fā)現(xiàn)成熟工具庫(kù)早就幫你把坑填平了

這篇文章就圍繞一個(gè)核心問(wèn)題展開(kāi):Spring Boot 項(xiàng)目里,驗(yàn)證碼到底該怎么實(shí)現(xiàn),才是又穩(wěn)又省事?

我們會(huì)完整對(duì)比兩種方案:

  1. 完全自定義實(shí)現(xiàn)驗(yàn)證碼生成邏輯(適合高度定制化需求)
  2. 基于 Hutool 快速集成多種驗(yàn)證碼類型(絕大多數(shù)項(xiàng)目的最優(yōu)解)

為什么圖形驗(yàn)證碼幾乎不可或缺?

驗(yàn)證碼的本質(zhì)不是“折磨用戶”,而是區(qū)分人和程序。

在以下場(chǎng)景中,它幾乎是必選項(xiàng):

  • 登錄接口防止BL破解
  • 注冊(cè)接口防止批量刷號(hào)
  • 密碼重置防止惡意撞庫(kù)
  • 重要操作前的人機(jī)確認(rèn)

通過(guò) 隨機(jī)字符 + 干擾元素 的方式,驗(yàn)證碼能顯著提高腳本攻擊成本,是最基礎(chǔ)、也是最有效的安全措施之一。

實(shí)現(xiàn)方式上,常見(jiàn)只有兩條路:

  1. 自己寫(xiě)一套驗(yàn)證碼生成邏輯
  2. 直接集成成熟工具庫(kù)

下面我們一條一條拆。

方案一:完全手寫(xiě)一個(gè)驗(yàn)證碼工具類

如果你的項(xiàng)目對(duì)驗(yàn)證碼樣式、字體、干擾規(guī)則有非常強(qiáng)的定制需求,那么手寫(xiě)一套邏輯是不可避免的。

驗(yàn)證碼工具類設(shè)計(jì)思路

我們需要完成幾件事:

  1. 隨機(jī)生成驗(yàn)證碼字符
  2. 繪制背景
  3. 繪制干擾線
  4. 繪制字符
  5. 將驗(yàn)證碼結(jié)果存入 Session
  6. 將圖片輸出到響應(yīng)流

項(xiàng)目目錄結(jié)構(gòu)

src/main/java
└── com
    └── icoderoad
        └── common
            └── util
                └── CaptchaCodeUtil.java

自定義驗(yàn)證碼工具類實(shí)現(xiàn)

package com.icoderoad.common.util;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class CaptchaCodeUtil {
    
    public static final String SESSION_KEY = "CAPTCHA_CODE";
    
    private final Random random = new Random();
    private final String codeSource = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
    private int width = 80;
    private int height = 26;
    private int codeLength = 4;
    private int lineCount = 40;
    
    private Font getFont() {
        return new Font("Fixedsys", Font.PLAIN, 18);
    }
    
    private Color randomColor(int min, int max) {
        min = Math.min(min, 255);
        max = Math.min(max, 255);
        int r = min + random.nextInt(max - min);
        int g = min + random.nextInt(max - min);
        int b = min + random.nextInt(max - min);
        return new Color(r, g, b);
    }
    
    private void drawLine(Graphics g) {
        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);
    }
    
    private String drawChar(Graphics g, int index) {
        g.setFont(getFont());
        g.setColor(randomColor(50, 160));
        String ch = String.valueOf(codeSource.charAt(random.nextInt(codeSource.length())));
        g.drawString(ch, 15 * index, 18);
        return ch;
    }
    
    public void generate(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
        
        for (int i = 0; i < lineCount; i++) {
            g.setColor(randomColor(120, 200));
            drawLine(g);
        }
        
        StringBuilder code = new StringBuilder();
        for (int i = 1; i <= codeLength; i++) {
            code.append(drawChar(g, i));
        }
        
        session.setAttribute(SESSION_KEY, code.toString());
        g.dispose();
        
        try {
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException("生成驗(yàn)證碼失敗", e);
        }
    }
}

Controller 中調(diào)用驗(yàn)證碼工具類

package com.icoderoad.web.controller;

import com.icoderoad.common.util.CaptchaCodeUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
public class CaptchaController {
    
    @GetMapping("/captcha/custom")
    public void customCaptcha(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("image/jpeg");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        
        new CaptchaCodeUtil().generate(request, response);
    }
}

?? 這種方式完全可控,但維護(hù)成本高、擴(kuò)展困難

方案二:使用 Hutool 快速集成驗(yàn)證碼(強(qiáng)烈推薦)

如果你不想把時(shí)間浪費(fèi)在“重復(fù)造輪子”上,Hutool 基本就是最優(yōu)解。

引入依賴

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-captcha</artifactId>
    <version>5.8.6</version>
</dependency>

Hutool 四種驗(yàn)證碼實(shí)戰(zhàn)示例

統(tǒng)一 Controller 路徑示例:com/icoderoad/web/controller/HutoolCaptchaController.java

1. 線條干擾驗(yàn)證碼(LineCaptcha)

@GetMapping("/captcha/line")
public void line(HttpServletResponse response) throws IOException {
    LineCaptcha captcha = CaptchaUtil.createLineCaptcha(130, 38, 5, 5);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

2. 圓圈干擾驗(yàn)證碼(CircleCaptcha)

@GetMapping("/captcha/circle")
public void circle(HttpServletResponse response) throws IOException {
    CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(130, 38, 5, 20);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

3. 扭曲驗(yàn)證碼(ShearCaptcha)

@GetMapping("/captcha/shear")
public void shear(HttpServletResponse response) throws IOException {
    ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(130, 38, 5, 5);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

4. GIF 動(dòng)態(tài)驗(yàn)證碼(GifCaptcha)

@GetMapping("/captcha/gif")
public void gif(HttpServletResponse response) throws IOException {
    GifCaptcha captcha = CaptchaUtil.createGifCaptcha(130, 38, 5);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

自定義驗(yàn)證碼內(nèi)容(數(shù)字 / 算術(shù))

純數(shù)字驗(yàn)證碼

@GetMapping("/captcha/number")
public void number(HttpServletResponse response) throws IOException {
    RandomGenerator generator = new RandomGenerator("0123456789", 4);
    LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 80);
    captcha.setGenerator(generator);
    captcha.createCode();
    captcha.write(response.getOutputStream());
}

算術(shù)驗(yàn)證碼(推薦)

@GetMapping("/captcha/math")
public void math(HttpServletResponse response, HttpSession session) throws IOException {
    ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 45, 4, 4);
    captcha.setGenerator(new MathGenerator());
    captcha.createCode();
    session.setAttribute("MATH_CODE", captcha.getCode());
    captcha.write(response.getOutputStream());
}

接口測(cè)試建議(Apifox)

  • 使用 GET 請(qǐng)求訪問(wèn)驗(yàn)證碼接口
  • 響應(yīng)應(yīng)為圖片而非亂碼
  • 多次刷新驗(yàn)證碼應(yīng)變化
  • 若不變化,優(yōu)先檢查緩存頭設(shè)置

關(guān)鍵實(shí)踐建議

  1. 驗(yàn)證碼值必須存 Session / Redis
  2. 驗(yàn)證成功后立即清除
  3. 驗(yàn)證碼接口應(yīng)限流
  4. 高安全場(chǎng)景可疊加短信 / IP 風(fēng)控

結(jié)語(yǔ):驗(yàn)證碼不是炫技,而是工程取舍

  • 需要極致定制 → 自定義實(shí)現(xiàn)
  • 追求效率與穩(wěn)定 → Hutool 一步到位

在真實(shí)項(xiàng)目里,99% 的情況你都不需要自己畫(huà)驗(yàn)證碼。把精力留給真正有價(jià)值的業(yè)務(wù)邏輯,才是成熟工程師的選擇。

到此這篇關(guān)于Spring Boot使用Hutool快速集成驗(yàn)證碼的文章就介紹到這了,更多相關(guān)SpringBoot Hutool集成驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

邵武市| 牟定县| 汶上县| 鹤山市| 清徐县| 武安市| 静乐县| 塔城市| 凤山县| 仪陇县| 封丘县| 朔州市| 嘉鱼县| 松溪县| 六盘水市| 桦川县| 乌兰浩特市| 临西县| 文昌市| 武川县| 永泰县| 麻城市| 大竹县| 高台县| 咸阳市| 穆棱市| 汉川市| 广饶县| 固始县| 玉溪市| 嘉禾县| 吉安市| 忻州市| SHOW| 门头沟区| 青海省| 台南县| 桂平市| 沈阳市| 雷山县| 通城县|