验证码案例

目录

前言

一、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;
    }
}
相关推荐
闲人编程10 天前
爬虫反爬机制和解决方案
开发语言·c++·爬虫·python·验证码
276695829212 天前
阿里1688 阿里滑块 231滑块 x5sec分析
java·python·go·验证码·1688·阿里滑块·231滑块
亿牛云爬虫专家1 个月前
SeleniumBase在无头模式下绕过验证码的完整指南
selenium·自动化·爬虫代理·验证码·代理ip·seleniumbase·无头模式
代码讲故事2 个月前
免费开源的功能强大并且识别率非常准确的验证码识别开源项目
开源·免费·登录·验证码·文字识别·图片识别·动态识别
zzzzzzzz'3 个月前
个人旅游网(2)——功能详解——用户登录注册功能
java·redis·web·登录·注册·验证码
Soujer3 个月前
AList嵌入动态验证码实现动态校验
验证码·alist·动态验证码
楠枬3 个月前
SpringBoot实现图形验证码
java·spring boot·后端·验证码
码王吴彦祖4 个月前
某RED书旋转验证码标注工具
爬虫·验证码
码农研究僧4 个月前
Springboot项目的行为验证码AJ-Captcha(源码解读)
java·spring boot·后端·验证码·captcha
rookiepm4 个月前
腾讯云发送短信验证码
云计算·腾讯云·验证码·短信