zoukankan      html  css  js  c++  java
  • JAVA实用案例之验证码开发

    验证码在很多地方都会遇到,实现的方法和形式也有很多,主要的目的就是为了安全,防止一些恶意的攻击等。说实话那么多年竟然没注意过这东西,原理很简单,贴出来给大家做个参考。

    1、简单介绍

    一般稍微有些经验的程序员都不会再自己写原生验证码生成了,因为各种强大的开源组件,足以解决我们大部分的需求。但是,毕竟也是刚接触这东西,还需要从原理入手的。

    项目效果图:

    下面我就简单介绍下原生和使用开源项目kaptcha生成验证码的两种形式。

    2、jdk原生生成验证码

    效果:

    2.1 验证码生成的流程

    1、定义BufferedImage(图像数据缓冲区)对象

    2、获得Graphics对象

    3、随机生成验证码字母或者数字

    4、使用Graphics绘制图片

    5、记录验证码信息到session或数据库,以便校验

    5、ImageIO输出图片到客户端

    2.2 代码讲解

    这里我就不整合框架了,简单用servlet讲下步骤,框架中也是这样做

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
            //定义BufferedImage(图像数据缓冲区)对象
            BufferedImage bi = new BufferedImage(68,22,BufferedImage.TYPE_INT_RGB);
            //绘制图片
            Graphics g = bi.getGraphics();
            //背景色
            Color c = new Color(200,150,255);
            g.setColor(c);
            //图片坐标
            g.fillRect(0, 0, 68, 22);
            //验证码选取
            char[] ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
            Random r = new Random();
            int len=ch.length,index;
            StringBuffer sb = new StringBuffer();
            for(int i=0; i<4; i++){
                index = r.nextInt(len);
                g.setColor(new Color(r.nextInt(88),r.nextInt(188),r.nextInt(255)));
                Font ft = new Font(Font.SANS_SERIF, Font.BOLD, 16);
                g.setFont(ft);
                g.drawString(ch[index]+"", (i*15)+3, 18);
                sb.append(ch[index]);
            }
    //打印验证码,项目中用日志 System.out.println(sb.toString());
         //验证码写到session request.getSession().setAttribute(
    "checkCode", sb.toString()); //ImageIO写出图片 ImageIO.write(bi, "JPG", response.getOutputStream()); }

    jsp:

     <form action="XX" method="get">
        验证码:<input type="text" name="checkcode"/>
        <img alt="点击更换验证码" id="imagecode" onclick="this.src='/servlet/ImageServlet?random='+Math.random();" src="/servlet/ImageServlet"/>
        <input type="submit" value="提交">
      </form>

     相信稍微有些经验的同学看过上面的代码都能理解其中的原理吧。至于后面的校验相信大家都会的。

    下面我重点讲下使用kaptcha开源组件生成验证码的流程,这里我会用servlet和springboot+springmvc的方式分别进行下介绍。

    3、使用kaptcha组件生成验证码

    既然说到开源组件,必然功能是强大的,还是先看效果图!

    数字字母组合

    数字字母汉字组合

    算数计算

    3.1 kaptcha的参数详解

    Constant 描述 默认值
    kaptcha.border 图片边框,合法值:yes , no yes
    kaptcha.border.color 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. black
    kaptcha.border.thickness 边框厚度,合法值:>0 1
    kaptcha.image.width 图片宽 200
    kaptcha.image.height 图片高 50
    kaptcha.producer.impl 图片实现类 com.google.code.kaptcha.impl.DefaultKaptcha
    kaptcha.textproducer.impl 文本实现类 com.google.code.kaptcha.text.impl.DefaultTextCreator
    kaptcha.textproducer.char.string 文本集合,验证码值从此集合中获取 abcde2345678gfynmnpwx
    kaptcha.textproducer.char.length 验证码长度 5
    kaptcha.textproducer.font.names 字体 Arial, Courier
    kaptcha.textproducer.font.size 字体大小 40px
    kaptcha.textproducer.font.color 字体颜色,合法值: r,g,b  或者 white,black,blue. black
    kaptcha.textproducer.char.space 文字间隔 2
    kaptcha.noise.impl 干扰实现类 com.google.code.kaptcha.impl.DefaultNoise
    kaptcha.noise.color 干扰颜色,合法值: r,g,b 或者 white,black,blue. black
    kaptcha.obscurificator.impl 图片样式:
    水纹com.google.code.kaptcha.impl.WaterRipple
    鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
    阴影com.google.code.kaptcha.impl.ShadowGimpy
    com.google.code.kaptcha.impl.WaterRipple
    kaptcha.background.impl 背景实现类 com.google.code.kaptcha.impl.DefaultBackground
    kaptcha.background.clear.from 背景颜色渐变,开始颜色 light grey
    kaptcha.background.clear.to 背景颜色渐变,结束颜色 white
    kaptcha.word.impl 文字渲染器 com.google.code.kaptcha.text.impl.DefaultWordRenderer
    kaptcha.session.key session key KAPTCHA_SESSION_KEY
    kaptcha.session.date session date KAPTCHA_SESSION_DATE

    3.2 代码讲解

    1、servlet方式

    上图可以看到,kaptcha处理验证码的类是KaptchaServlet。这里我们就可以像原生的方式一样直接请求这个servlet,这里主要讲下使用servlet和使用框架的时候参数配置是不用的,servlet的是配置在web.xml中的,形式如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
    
        <!-- 登陆验证码Kaptcha 2-->
        <servlet>
            <servlet-name>Kaptcha</servlet-name>
            <servlet-class>
                com.google.code.kaptcha.servlet.KaptchaServlet
            </servlet-class>
            <init-param>
                <description>图片边框,合法值:yes , no</description>
                <param-name>kaptcha.border</param-name>
                <param-value>yes</param-value>
            </init-param>
            <init-param>
                <description>
                    边框颜色,合法值: r,g,b (and optional alpha) 或者
                    white,black,blue.
                </description>
                <param-name>kaptcha.border.color</param-name>
                <param-value>black</param-value>
            </init-param>
            <init-param>
                <description>边框厚度,合法值:>0</description>
                <param-name>kaptcha.border.thickness</param-name>
                <param-value>1</param-value>
            </init-param>
            <init-param>
                <description>图片宽 200</description>
                <param-name>kaptcha.image.width</param-name>
                <param-value>200</param-value>
            </init-param>
            <init-param>
                <description>图片高 50</description>
                <param-name>kaptcha.image.height</param-name>
                <param-value>50</param-value>
            </init-param>
            <init-param>
                <description>图片实现类</description>
                <param-name>kaptcha.producer.impl</param-name>
                <param-value>
                    com.google.code.kaptcha.impl.DefaultKaptcha
                </param-value>
            </init-param>
            <init-param>
                <description>文本实现类</description>
                <param-name>kaptcha.textproducer.impl</param-name>
                <param-value>
                    com.google.code.kaptcha.text.impl.DefaultTextCreator
                </param-value>
            </init-param>
            <init-param>
                <description>验证码长度 5</description>
                <param-name>kaptcha.textproducer.char.length</param-name>
                <param-value>5</param-value>
            </init-param>
            <init-param>
                <description>字体 Arial, Courier</description>
                <param-name>kaptcha.textproducer.font.names</param-name>
                <param-value>Arial, Courier</param-value>
            </init-param>
            <init-param>
                <description>字体大小 40px.</description>
                <param-name>kaptcha.textproducer.font.size</param-name>
                <param-value>40</param-value>
            </init-param>
            <init-param>
                <description>
                    字体颜色,合法值: r,g,b 或者 white,black,blue.
                </description>
                <param-name>kaptcha.textproducer.font.color</param-name>
                <param-value>black</param-value>
            </init-param>
            <init-param>
                <description>文字间隔 2</description>
                <param-name>kaptcha.textproducer.char.space</param-name>
                <param-value>2</param-value>
            </init-param>
            <init-param>
                <description>干扰实现类</description>
                <param-name>kaptcha.noise.impl</param-name>
                <param-value>
                    com.google.code.kaptcha.impl.DefaultNoise
                </param-value>
            </init-param>
            <init-param>
                <description>
                    干扰颜色,合法值: r,g,b 或者 white,black,blue.
                </description>
                <param-name>kaptcha.noise.color</param-name>
                <param-value>black</param-value>
            </init-param>
            <init-param>
                <description>
                    图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple
                    鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
                    阴影com.google.code.kaptcha.impl.ShadowGimpy
                </description>
                <param-name>kaptcha.obscurificator.impl</param-name>
                <param-value>
                    com.google.code.kaptcha.impl.WaterRipple
                </param-value>
            </init-param>
            <init-param>
                <description>背景实现类</description>
                <param-name>kaptcha.background.impl</param-name>
                <param-value>
                    com.google.code.kaptcha.impl.DefaultBackground
                </param-value>
            </init-param>
            <init-param>
                <description>背景颜色渐变,开始颜色</description>
                <param-name>kaptcha.background.clear.from</param-name>
                <param-value>green</param-value>
            </init-param>
            <init-param>
                <description>背景颜色渐变,结束颜色</description>
                <param-name>kaptcha.background.clear.to</param-name>
                <param-value>white</param-value>
            </init-param>
            <init-param>
                <description>文字渲染器</description>
                <param-name>kaptcha.word.impl</param-name>
                <param-value>
                    com.google.code.kaptcha.text.impl.DefaultWordRenderer
                </param-value>
            </init-param>
            <init-param>
                <description>
                    session中存放验证码的key键
                </description>
                <param-name>kaptcha.session.key</param-name>
                <param-value>KAPTCHA_SESSION_KEY</param-value>
            </init-param>
            <init-param>
                <description>
                    The date the kaptcha is generated is put into the
                    HttpSession. This is the key value for that item in the
                    session.
                </description>
                <param-name>kaptcha.session.date</param-name>
                <param-value>KAPTCHA_SESSION_DATE</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>Kaptcha</servlet-name>
            <url-pattern>/randomcode.jpg</url-pattern>
        </servlet-mapping>
    
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    </web-app>

    2、使用springboot+springmvc框架

     这里新建一个maven项目,添加依赖

    <dependency>  
        <groupId>com.github.penggle</groupId>  
        <artifactId>kaptcha</artifactId>  
        <version>2.3.2</version>  
    </dependency>  

    controller:

    @Controller
    public class UserController {
        @Autowired
        private Producer captchaProducer;
    
        @RequestMapping("/ran/random")
        public void checkCode(HttpServletRequest request,HttpServletResponse response) throws IOException{
            byte[] captchaChallengeAsJpeg = null;    
            ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();    
            try {    
                //生产验证码字符串并保存到session中  
                String createText = captchaProducer.createText();  
                request.getSession().setAttribute("checkCode", createText);  
                //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中  
                BufferedImage challenge = captchaProducer.createImage(createText);  
                ImageIO.write(challenge, "jpg", jpegOutputStream);  
            } catch (IllegalArgumentException e) {    
                response.sendError(response.SC_NOT_FOUND);    
                return;    
            }   
    
            //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组  
            captchaChallengeAsJpeg = jpegOutputStream.toByteArray();    
            response.setHeader("Cache-Control", "no-store");    
            response.setHeader("Pragma", "no-cache");    
            response.setDateHeader("Expires", 0);    
            response.setContentType("image/jpeg");    
            ServletOutputStream responseOutputStream =    
                    response.getOutputStream();    
            responseOutputStream.write(captchaChallengeAsJpeg);    
            responseOutputStream.flush();    
            responseOutputStream.close();    
        }  
    }

    配置类CaptchaConfig:

    这里@value是为了将相关属性写进application.properties,避免硬编码,为了方便测试我先注掉

    package com.allan.base;
    
    import java.util.Properties;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.google.code.kaptcha.impl.DefaultKaptcha;
    import com.google.code.kaptcha.util.Config;
    /**
     * 验证码配置类
     * @author zhangzhuo
     *
     */
    @Configuration
    public class CaptchaConfig {
        @Value("${kaptcha.border}")
        private  String  border;
        @Value("${kaptcha.border.color}")
        private  String  borderColor;
        @Value("${kaptcha.textproducer.font.color}")
        private  String  fontColor;
        @Value("${kaptcha.image.width}")
        private  String  imageWidth;
        @Value("${kaptcha.image.height}")
        private  String  imageHeight;
        @Value("${kaptcha.session.key}")
        private  String  sessionKey;
        @Value("${kaptcha.textproducer.char.length}")
        private  String  charLength;
        @Value("${kaptcha.textproducer.font.names}")
        private  String  fontNames;
    
        @Bean(name="captchaProducer")
        public DefaultKaptcha getKaptchaBean(){
            DefaultKaptcha defaultKaptcha=new DefaultKaptcha();
            Properties properties=new Properties();
          /*  properties.setProperty("kaptcha.border", border);
            properties.setProperty("kaptcha.border.color", borderColor);
            properties.setProperty("kaptcha.textproducer.font.color", fontColor);
            properties.setProperty("kaptcha.image.width", imageWidth);
            properties.setProperty("kaptcha.image.height", imageHeight);
            properties.setProperty("kaptcha.session.key", sessionKey);
            properties.setProperty("kaptcha.textproducer.char.length", charLength);
            properties.setProperty("kaptcha.textproducer.font.names", fontNames);
            properties.setProperty("kaptcha.textproducer.font.size", "30"); */
            properties.setProperty("kaptcha.border", "yes");  
            properties.setProperty("kaptcha.border.color", "105,179,90");  
            properties.setProperty("kaptcha.textproducer.font.color", "blue");  
            properties.setProperty("kaptcha.image.width", "90");  
            properties.setProperty("kaptcha.image.height", "28");  
            properties.setProperty("kaptcha.textproducer.font.size", "28");  
            properties.setProperty("kaptcha.session.key", "code");  
            properties.setProperty("kaptcha.textproducer.char.length", "4");  
            properties.setProperty("kaptcha.textproducer.char.space", "2");
            properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy"); 
            properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
            properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");  
            Config config=new Config(properties);
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
    }

    启动类:

    package com.allan.server;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.context.annotation.ComponentScan;
    @EnableAutoConfiguration
    @ComponentScan(basePackages = {"com.allan.controller","com.allan.service","com.allan.base"})
    @MapperScan(basePackages = "com.allan.mapper")
    public class StartApp {
        public static void main(String[] args) {
            SpringApplication.run(StartApp.class, args);
        }
    }

    jsp:

    <p class="main">
          <label>验证码: </label> <input name="randomCode"
                   onkeyup="enterSubmit(event)" placeholder="验证码"
                    style=" 105px;" maxlength="4" /> <span class="yzm-pic">
          <img src="/ran/random" alt="验证码,点击图片更换"
                                onclick="this.src='/ran/random?random='+Math.random();" />
                            </span>
    </p>

    最终的效果图:

    最后说下springboot除了上面写代码的形式还可以写成下面的配置文件:

    可以定义applicationcontext-check.xml

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
        <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">  
            <property name="config">  
                <bean class="com.google.code.kaptcha.util.Config">  
                    <constructor-arg type="java.util.Properties">  
                        <props>  
                            <prop key = "kaptcha.border ">yes</prop>  
                                <prop key="kaptcha.border.color">105,179,90</prop>  
                                <prop key="kaptcha.textproducer.font.color">blue</prop>  
                                <prop key="kaptcha.image.width">100</prop>  
                                <prop key="kaptcha.image.height">50</prop>  
                                <prop key="kaptcha.textproducer.font.size">27</prop>  
                                <prop key="kaptcha.session.key">code</prop>  
                                <prop key="kaptcha.textproducer.char.length">4</prop>  
                                <prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop>  
                                <prop key="kaptcha.textproducer.char.string">0123456789ABCEFGHIJKLMNOPQRSTUVWXYZ</prop>  
                                <prop key="kaptcha.obscurificator.impl">com.google.code.kaptcha.impl.WaterRipple</prop>  
                                <prop key="kaptcha.noise.color">black</prop>  
                                <prop key="kaptcha.noise.impl">com.google.code.kaptcha.impl.DefaultNoise</prop>  
                                <prop key="kaptcha.background.clear.from">185,56,213</prop>  
                                <prop key="kaptcha.background.clear.to">white</prop>  
                                <prop key="kaptcha.textproducer.char.space">3</prop>  
                        </props>  
                    </constructor-arg>  
                </bean>  
            </property>  
        </bean>  
      
    </beans>  

    如果写配置文件,这边在启动的时候需要引入配置文件

    @ImportResource(locations={"classpath:applicationcontext-check.xml"})  

    基本上就是这些,至于汉字组合或者计算形式的验证码,这边我们只要实现kaptcha.textproducer.impl和com.google.code.kaptcha.servlet.KaptchaServlet这两个类就行了,大家可以看下源码,很简单的。

    最后的最后,如果有对于springboot不熟悉的同学可以看下我整理的这些文章,相信会有些帮助的http://www.cnblogs.com/allanzhang/category/1000281.html

    jdk版源码:https://git.oschina.net/allanzhang/checkcode.git

  • 相关阅读:
    javascript Date format(js日期格式化)
    给上传文件的input控件“美容”
    判断json数据是否为空
    C#实现SQL数据库备份与恢复
    jquery读取html5的data-属性
    PowerDesigner使用教程
    PowerDesigner使用教程|使用方法
    [转][南京米联ZYNQ深入浅出]第二季更新完毕课程共计16节课
    DefWindowProc是一个会产生消息的函数
    BeginPaint 和 GetDC 的一个区别
  • 原文地址:https://www.cnblogs.com/laoyeye/p/6914704.html
Copyright © 2011-2022 走看看