验证码案例

目录

前言

一、Hutool工具介绍

[1.1 Maven](#1.1 Maven)

[1.2 介绍](#1.2 介绍)

[1.3 实现类](#1.3 实现类)

二、验证码案例

[2.1 需求](#2.1 需求)

[2.2 约定前后端交互接口](#2.2 约定前后端交互接口)

[2.2.1 需求分析](#2.2.1 需求分析)

[2.2.2 接口定义](#2.2.2 接口定义)

[2.3 后端生成验证码](#2.3 后端生成验证码)

[2.4 前端接收验证码图片](#2.4 前端接收验证码图片)

[2.5 后端校验验证码](#2.5 后端校验验证码)

[2.6 前端校验验证码](#2.6 前端校验验证码)

[2.7 后端完整代码](#2.7 后端完整代码)


前言

验证码实现方式很多,可以前端实现,也可以后端实现,网上也有比较多的插件或者工具包可以使用,咱们选择使用Hutool提供的小工具来实现。

一、Hutool工具介绍

Hutool是一个Java工具包类库,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类。Hutool官网:https://hutool.cn/

1.1 Maven

如果你想在项目中使用Hutool中的某个模块,在项目的pom.xml的dependencies中加入以下内容:

XML 复制代码
<dependency>
    <groupId>cn.hutool</groupId>
	<artifactId>hutool-captcha</artifactId>
	<version>5.8.22</version>
</dependency>

1.2 介绍

验证码功能位于cn.hutool.captcha包中,核心接口为ICaptcha,此接口定义了以下方法:

  • createCode 创建验证码,实现类需同时生成随机验证码字符串和验证码图片
  • getCode 获取验证码的文字内容
  • verify 验证验证码是否正确,建议忽略大小写
  • write 将验证码图片写出到目标流中

其中write方法只有一个OutputStreamICaptcha实现类可以根据这个方法封装写出到文件等方法。

AbstractCaptcha为一个ICaptcha抽象实现类,此类实现了验证码文本生成、非大小写敏感的验证、写出到流和文件等方法,通过继承此抽象类只需实现createImage方法定义图形生成规则即可。

1.3 实现类

LineCaptcha线段干扰的验证码

贴栗子:

java 复制代码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.lang.Console;

public class LineCaptchaTest {
    public static void main(String[] args) {
        //定义图形验证码的长和宽
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        //图形验证码写出,可以写出到文件,也可以写出到流
        lineCaptcha.write("d:/line.png");
        //输出code
        Console.log(lineCaptcha.getCode());
        //验证图形验证码的有效性,返回boolean值
        lineCaptcha.verify("1234");

        //重新生成验证码
        lineCaptcha.createCode();
        lineCaptcha.write("d:/line.png");
        //新的验证码
        Console.log(lineCaptcha.getCode());
        //验证图形验证码的有效性,返回boolean值
        lineCaptcha.verify("1234");
    }
}

控制台截图生成的验证码:

在写入的路径中查看代码生成的验证码截图:

**CircleCaptcha**圆圈干扰验证码

java 复制代码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.lang.Console;

public class CircleCaptchaTest {
    public static void main(String[] args) {
        //定义图形验证码的长、宽、验证码字符数、干扰元素个数
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        //CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);
        //图形验证码写出,可以写出到文件,也可以写出到流
        captcha.write("d:/circle.png");
        //输出code
        Console.log(captcha.getCode());
        //验证图形验证码的有效性,返回boolean值
        captcha.verify("1234");
    }
}

控制台截图生成的验证码:

在写入的路径中查看代码生成的验证码截图:

ShearCaptcha 扭曲干扰验证码

java 复制代码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.lang.Console;

public class ShearCaptchaTest {
    public static void main(String[] args) {
        //定义图形验证码的长、宽、验证码字符数、干扰线宽度
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 100, 4, 4);
        //ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);
        //图形验证码写出,可以写出到文件,也可以写出到流
        captcha.write("d:/shear.png");
        //输出code
        Console.log(captcha.getCode());
        //验证图形验证码的有效性,返回boolean值
        captcha.verify("1234");
    }
}

控制台截图生成的验证码:

在写入的路径中查看代码生成的验证码截图:

二、验证码案例

2.1 需求

需求如下:

  • 页面生成验证码
  • 输入验证码,点击提交,验证用户输入验证码是否正确,正确则进行页面跳转

2.2 约定前后端交互接口

2.2.1 需求分析

后端需要提供两个服务:

  • 生成验证码,并返回验证码
  • 校验验证码是否正确

2.2.2 接口定义

1、生成验证码:

url:/captcha/get

param:无

return:图片的内容

2、校验验证码

url:/captcha/check

param:inputCode

return:true/false

2.3 后端生成验证码

java 复制代码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
@RequestMapping("/captcha")
public class CaptchaController {
    @RequestMapping("/get")
    public void getCaptcha(HttpServletResponse response) {
        //定义图形验证码的长和宽
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        //图像验证码写出,可以写出到文件,也可以写出到流,此处写出到流
        try {
            lineCaptcha.write(response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

小技巧:在我们每写完一个后端代码模块时,我们可以进行测试,看是否有错误,避免后续代码量过多发生错误时不知道哪块出错。

根据后端定义的url进行测试截图:

2.4 前端接收验证码图片

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">

  <title>验证码</title>
  <style>
    #inputCaptcha {
      height: 30px;
      vertical-align: middle; 
    }
    #verificationCodeImg{
      vertical-align: middle; 
    }
    #checkCaptcha{
      height: 40px;
      width: 100px;
    }
  </style>
</head>

<body>
  <h1>输入验证码</h1>
  <div id="confirm">
    <input type="text" name="inputCaptcha" id="inputCaptcha">
    <img id="verificationCodeImg" src="/captcha/get" style="cursor: pointer;" title="看不清?换一张" />
    <input type="button" value="提交" id="checkCaptcha">
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
  <script>
    
    $("#verificationCodeImg").click(function(){
      $(this).hide().attr('src', '/captcha/get?dt=' + new Date().getTime()).fadeIn();
    });

    $("#checkCaptcha").click(function () {
        alert("验证码校验");
    });

  </script>
</body>

</html>

验证前端是否有问题:

2.5 后端校验验证码

java 复制代码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.example.demo.model.CaptchaProperties;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Date;

@RestController
@RequestMapping("/captcha")
public class CaptchaController {
    private final static long session_valid_timeout = 60 * 1000;

    @Autowired
    private CaptchaProperties captchaProperties;
    
    @RequestMapping("/check")
    public Boolean check(HttpSession session, String inputCode) {
        //验证码输入的内容和用户输入的进行比较
        //从session获取信息
        if (!StringUtils.hasLength(inputCode)) {
            return false;
        }
        String savedCode = (String) session.getAttribute(captchaProperties.getSession().getKey());
        Date saveDate = (Date) session.getAttribute(captchaProperties.getSession().getDate());
        if (inputCode.equalsIgnoreCase(savedCode)) {
            //判断验证码是否过期
            if (saveDate != null && System.currentTimeMillis() - saveDate.getTime() < session_valid_timeout) {
                return true;
            }
            return true;
        }
        return false;
    }
}

检查校验验证码是否存在问题:

1、先查看后端生成的验证码

2、根据校验验证的url进行验证

首先先输入错误的验证码观察返回ture或者false,如果返回false证明验证码输入错误或者过期,否则反正true。

先输入错误的验证码1234截图:

再输入正确的验证码截图:

2.6 前端校验验证码

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">

  <title>验证码</title>
  <style>
    #inputCaptcha {
      height: 30px;
      vertical-align: middle; 
    }
    #verificationCodeImg{
      vertical-align: middle; 
    }
    #checkCaptcha{
      height: 40px;
      width: 100px;
    }
  </style>
</head>

<body>
  <h1>输入验证码</h1>
  <div id="confirm">
    <input type="text" name="inputCaptcha" id="inputCaptcha">
    <img id="verificationCodeImg" src="/captcha/get" style="cursor: pointer;" title="看不清?换一张" />
    <input type="button" value="提交" id="checkCaptcha">
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
  <script>
    
    $("#verificationCodeImg").click(function(){
      $(this).hide().attr('src', '/captcha/get?dt=' + new Date().getTime()).fadeIn();
    });

    $("#checkCaptcha").click(function () {
        $.ajax({
          url: "/captcha/check",
          type: "post",
          data: {
            inputCode: $("#inputCaptcha").val()
          },
          success: function(result) {
            if (result) {
              location.href = "success.html";
            } else {
              alert("验证码错误或者过期");
            }
          }
        })
    });

  </script>
</body>

</html>
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>验证成功页</title>
</head>
<body>
    <h1>验证成功</h1>
</body>
</html>

运行截图:

2.7 后端完整代码

java 复制代码
package com.example.demo.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.example.demo.model.CaptchaProperties;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Date;

@RestController
@RequestMapping("/captcha")
public class CaptchaController {
    private final static long session_valid_timeout = 60 * 1000;

    @Autowired
    private CaptchaProperties captchaProperties;

    @RequestMapping("/get")
    public void getCaptcha(HttpSession session, HttpServletResponse response) {
        //定义图形验证码的长和宽
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
        //设置缓存类型
        response.setContentType("image/jpeg");
        //禁止缓存
        response.setHeader("Progma", "No-cache");
        //图像验证码写出,可以写出到文件,也可以写出到流,此处写出到流
        try {
            lineCaptcha.write(response.getOutputStream());
            //存储session
            session.setAttribute(captchaProperties.getSession().getKey(), lineCaptcha.getCode());
            session.setAttribute(captchaProperties.getSession().getDate(), new Date());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @RequestMapping("/check")
    public Boolean check(HttpSession session, String inputCode) {
        //验证码输入的内容和用户输入的进行比较
        //从session获取信息
        if (!StringUtils.hasLength(inputCode)) {
            return false;
        }
        String savedCode = (String) session.getAttribute(captchaProperties.getSession().getKey());
        Date saveDate = (Date) session.getAttribute(captchaProperties.getSession().getDate());
        if (inputCode.equalsIgnoreCase(savedCode)) {
            //判断验证码是否过期
            if (saveDate != null && System.currentTimeMillis() - saveDate.getTime() < session_valid_timeout) {
                return true;
            }
        }
        return false;
    }
}

配置文件:

XML 复制代码
captcha:
  width: 200
  height: 100
  session:
    key: captcha_session_key
    date: captcha_session_date

captcha配置:

java 复制代码
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "captcha")
@Data
public class CaptchaProperties {
    private Integer width;
    private Integer height;
    private Session session;

    @Data
    public static class Session {
        private String key;
        private String date;
    }
}
相关推荐
七禾页话7 天前
Springboot和vue前后端交互实现验证码登录
vue.js·spring boot·验证码
七禾页话8 天前
使用Java得hutool工具实现验证码登录
java·验证码
LKID体11 天前
滑块验证码,滑块和有缺口的背景
python·验证码
GGBondlctrl15 天前
【Spring】探秘 SpringBoot 配置文件:解锁验证码背后的实现逻辑
java·spring boot·验证码·hutool
sir.山18 天前
taro小程序进入腾讯验证码
小程序·taro·验证码·腾讯验证码·uniapp验证码·原生验证码
亿牛云爬虫专家1 个月前
使用 Puppeteer 绕过 Captcha:实现商家数据自动化采集
自动化·爬虫代理·验证码·puppeteer·代理ip·大众点评·captcha
闲人编程1 个月前
爬虫反爬机制和解决方案
开发语言·c++·爬虫·python·验证码
27669582921 个月前
阿里1688 阿里滑块 231滑块 x5sec分析
java·python·go·验证码·1688·阿里滑块·231滑块
亿牛云爬虫专家3 个月前
SeleniumBase在无头模式下绕过验证码的完整指南
selenium·自动化·爬虫代理·验证码·代理ip·seleniumbase·无头模式
代码讲故事3 个月前
免费开源的功能强大并且识别率非常准确的验证码识别开源项目
开源·免费·登录·验证码·文字识别·图片识别·动态识别