跳至主要內容

验证码

TenSoFlow...大约 5 分钟项目技术验证码

验证码

简介

验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试 )的缩写,是一种区分用户是计算机还是人的公共全自动程序。2002年路易斯和他的小伙伴在卡内基梅隆第一次提出了CAPTCHA(验证码)这样一个程序概念。该程序是指,向请求的发起方提出问题,能正确回答的即是人类,反之则为机器。这个程序基于这样一个重要假设:提出的问题要容易被人类解答,并且让机器无法解答。可以有效的防止某些特定程序以暴力方式不断进行登录尝试。验证码的不断发展其实是随着其破解功能的逐步强大而跟着演进的,这是一个攻防博弈的精彩世界

手写图形验证码

如果设计的图形验证码干扰项不是很多,则非常不安全,一些机器学习技术可以轻松实现识别,并且准确率是100%。具体见"我的笔记"中的《Tess4j光学识别》这篇文章

package com.ctg.MyAllClass.LittleTools;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

/**
 * 1. @ClassDescription:自动生成一张验证码图片
 * 2. @author: TenSoFlow
 * 3. @date: 2023年10月11日 14:25
 */
@SuppressWarnings("all")
public class Captcha
{
    // 验证码图片宽度
    private static int width = 150;
    // 验证码图片高度
    private static int height = 50;
    // 图片后缀
    private static String type = "jpg";
    // 图片名称
    private static String name = "test";
    // 设置图片的生成位置
    private static String position = "D:\\Desktop\\";
    // 验证码能包含的符号 没有0与o 和l与1 因为他们很相似
    private static String str = "abcdefghigkmnpqrstuvwxyz23456789";
    // 图片类型
    private static int imageType = BufferedImage.TYPE_INT_RGB;
    // 生成文件对象
    private static File file = new File( position + name + "." + type);
    public static void main(String[] args) throws IOException
    {
        // 1.准备画板或者叫一张白纸
        BufferedImage image = new BufferedImage(width,height,imageType);
        // 2.准备画笔
        Graphics graphics = image.getGraphics();
        // 给笔设置颜色
        graphics.setColor(Color.YELLOW);
        // 给笔设置字体
        graphics.setFont(new Font("楷体",Font.BOLD,25));
        // 用笔画四个字符串(圆 矩形都可以画) 参数基本都是内容加位置
        int x = 35;
        int y = 35;
        Random random = new Random();
        for(int i=0;i<4;i++)
        {
            // 随机取一个字符
            String temp = String.valueOf(str.charAt(random.nextInt(str.length())));
            // 把字符画上去
            graphics.drawString(temp,x,y);
            x += 30;
        }
        // 3.画干扰线
        for(int i=0;i<20;i++)
        {
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1,y1,x2,y2);
        }
        // 4.绘制完成 生成图片 存在本地磁盘
        ImageIO.write(image,type,file);
    }
}

项目中使用手写图形验证码

SpringBoot项目中前端发送请求,后端响应一张验证码图片的实现。

前端

<img id="captcha" src="http://localhost:8080/login/verifyCode"onclick="ChangeVerifyCode(this)">

<script>
  var baseURL = 'http://localhost:8080'
  // 更新验证码函数
  function ChangeVerifyCode(obj)
  {
    // 得到当前时间
    var timeNow = new Date().getTime();
    obj.src = baseURL + "/login/verifyCode?d=" + timeNow;
  }
</script>

后端

GenerateImage生成图像工具类

package com.utils;

import lombok.Data;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Random;

/**
 * 1. @ClassDescription:产生验证码图片
 * 2. @author: TenSoFlow
 * 3. @date: 2023年10月11日 17:03
 */
@Data
public class GenerateImage
{
    // 验证码真实字符串
    private String str = "";

    // 验证码图片
    private ByteArrayInputStream image;

    // 验证码图片宽度
    private static int width = 150;

    // 验证码图片高度
    private static int height = 50;

    // 构造方法创建对象时就使用init方法创建好图片存到ByteArrayInputStream image中
    private GenerateImage()
    {
        init();
    }

    // 得到该工具类对象
    public static GenerateImage getInstance()
    {
        return new GenerateImage();
    }

    // 图片后缀
    private static String type = "jpg";

    // 验证码能包含的符号 没有0与o 和l与1 因为他们很相似
    private static String strs = "abcdefghigkmnpqrstuvwxyz23456789";
    // 图片类型
    private static int imageType = BufferedImage.TYPE_INT_RGB;

    private void init()
    {
        // 1.准备画板或者叫一张白纸
        BufferedImage image = new BufferedImage(width,height,imageType);
        // 2.准备画笔
        Graphics graphics = image.getGraphics();
        // 给笔设置颜色
        graphics.setColor(Color.YELLOW);
        // 给笔设置字体
        graphics.setFont(new Font("楷体",Font.BOLD,25));
        // 用笔画四个字符串(圆 矩形都可以画) 参数基本都是内容加位置
        int x = 35;
        int y = 35;
        Random random = new Random();
        for(int i=0;i<4;i++)
        {
            // 随机取一个字符
            String temp = String.valueOf(strs.charAt(random.nextInt(strs.length())));
            str += temp;
            // 把字符画上去
            graphics.drawString(temp,x,y);
            x += 30;
        }
        // 3.画干扰线
        for(int i=0;i<20;i++)
        {
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1,y1,x2,y2);
        }
        // 4.绘制完成 生成图片
        graphics.dispose();
        ByteArrayInputStream inputStream = null;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            ImageOutputStream imageOut = ImageIO.createImageOutputStream(outputStream);
            ImageIO.write(image,type,imageOut);
            imageOut.close();
            inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        }catch (Exception e)
        {
            System.out.println("验证码图片生成失败");
        }
        this.image = inputStream;
    }
}

LoginController类

package com.tensoflow.controller;

import com.utils.GenerateImage;
import com.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;

/**
 * 1. @ClassDescription:生成验证码的Controller类
 * 2. @author: TenSoFlow
 * 3. @date: 2023年10月11日 17:13
 */
@CrossOrigin(origins = "http://localhost:63342" , allowCredentials = "true")
@RestController
@RequestMapping("/login")
@Slf4j
public class LoginController
{
    @GetMapping("/verifyCode")
    public void generateImage(HttpServletRequest request, HttpServletResponse response)
    {
        // 打印日志
        log.info("更新验证码");

        // 得到工具类
        GenerateImage imageUtil = GenerateImage.getInstance();

        // 得到输入流
        ByteArrayInputStream image = imageUtil.getImage();

        // 得到真实验证码文字并存入session中
        String verifyCode = imageUtil.getStr();
        request.getSession().setAttribute("verifyCode",verifyCode);

        // 设置返回类型为图像
        response.setContentType("image/jpg");

        // 使用response返回图像
        byte[] bytes = new byte[1024];
        try(ServletOutputStream out = response.getOutputStream())
        {
            while(image.read(bytes) != -1)
            {
                out.write(bytes);
            }
        } catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }
}
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8