数字验证码

318 阅读1分钟

数字验证码

数字验证码的生成

生成验证码

@Data
public class ImageCode {
    //图形类容
    private String code;
    //图片
    private ByteArrayInputStream image;
    //长
    private int height=100;
    //宽
    private int width=400;

    public static ImageCode getInstance(){
        return new ImageCode();
    }
    private ImageCode(){
        //图形缓冲区,相当于黑板
        BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //给一支画笔
        Graphics graphics = image.getGraphics();
        //选择什么颜色的笔
        graphics.setColor(new Color(17,147,37));
        //拿笔去涂色,画一个矩形
        graphics.fillRect(0,0,width,height);
        //设置字体
        graphics.setFont(new Font("宋体",Font.PLAIN,30));
        //图片就中就设置为随机数
        Random random =new Random();
        this.code="";
        for(int i=0;i<6;i++){
            //生成随机数
            String value = String.valueOf(random.nextInt(10));
            //赋值给code
            this.code+=value;
            //设置画出字的颜色
            graphics.setColor(new Color(235,152,37));
            //设置画出字在矩形的位置
            graphics.drawString(value,(width/6)*i,40);
        }
        //收笔
        graphics.dispose();

        ByteArrayInputStream inputStream=null;

        try {
            ByteOutputStream outputStream =new ByteOutputStream();
            ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);

            ImageIO.write(image,"jpeg",imageOutputStream);
            inputStream=new ByteArrayInputStream(outputStream.toByteArray());
        }catch (Exception e){
            System.out.println("数字验证码创建失败");
        }
        this.image=inputStream;

    }

}

在控制层的方法

    String attrName="verifyCode";
    //控制层调用验证码
    @GetMapping("/generator")
    public void generatorCode(HttpServletRequest request,HttpServletResponse response){

        try {
            ImageCode imageCode =ImageCode.getInstance();
            //验证码的值
            String code = imageCode.getCode();

            request.getSession().setAttribute(attrName,code);
            //验证码的图片
            ByteArrayInputStream image=imageCode.getImage();
            response.setContentType("image/jpeg");
            byte[] bytes = new byte[1024];
            try(ServletOutputStream out =response.getOutputStream()) {
                while (image.read(bytes)!=-1){
                    out.write(bytes);
                }
            }
        }catch (Exception e){
            System.out.println("失败输出验证码");
        }
    }

运行效果

    //校验验证码
    @GetMapping("/verify")
    public String verify(String verifyCode, HttpServletRequest request){
        String s = request.getSession().getAttribute(attrName).toString();
        System.out.println("校验验证码");
        if(verifyCode.equals(s)){
            return "验证码校验通过";
        }
        return "验证码校验失败";
    }

校验成功

校验失败

数字验证码的破解

导入依赖

      	<!--光学识别 OCR-->
        <dependency>
            <groupId>net.sourceforge.tess4j</groupId>
            <artifactId>tess4j</artifactId>
            <version>4.5.4</version>
        </dependency>

可以在github.com/tesseract-o… 下载所需要的语言包

public class TesseractTest {

	public static void main(String[] args) throws TesseractException {
		//https://github.com/tesseract-ocr/tessdata 语言包
		ITesseract iTesseract = new Tesseract();
		// 语言包 加进来
		iTesseract.setDatapath("语言包的路径");
		//中文包
		iTesseract.setLanguage("chi_sim");
		//英文包
		//iTesseract.setLanguage("eng");

		File fileDir = new File("d:\data");
		for (File file: fileDir.listFiles()){
			String s = iTesseract.doOCR(file);
			System.out.println(file.getName()+ "识别后数字是:"+s);

		}
	}
}

需要破解的图片

识别后的结果:

防止办法

可以在验证码上面设置干扰,比如换字体颜色,在验证码上面增加线条,只要是人能识别出来, 机器识别不出来即可

在生成验证码的的代码可以加入划线,来干扰机器的识别率

            //划线,可以提高安全
            graphics.setColor(new Color(101,2,60));
            graphics.drawLine((width/6)*i,40,(width/6)*i+25,40-30);
            graphics.drawLine(40,(width/6)*i,40-30,(width/6)*i+25);