JAVA實用案例之驗證碼開發

驗證碼在不少地方都會遇到,實現的方法和形式也有不少,主要的目的就是爲了安全,防止一些惡意的攻擊等。說實話那麼多年居然沒注意過這東西,原理很簡單,貼出來給你們作個參考。html

一、簡單介紹

通常稍微有些經驗的程序員都不會再本身寫原生驗證碼生成了,由於各類強大的開源組件,足以解決咱們大部分的需求。可是,畢竟也是剛接觸這東西,還須要從原理入手的。java

項目效果圖:git

下面我就簡單介紹下原生和使用開源項目kaptcha生成驗證碼的兩種形式。程序員

二、jdk原生生成驗證碼

效果:github

2.1 驗證碼生成的流程

一、定義BufferedImage(圖像數據緩衝區)對象web

二、得到Graphics對象spring

三、隨機生成驗證碼字母或者數字數據庫

四、使用Graphics繪製圖片數組

五、記錄驗證碼信息到session或數據庫,以便校驗安全

五、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的方式分別進行下介紹。

三、使用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 代碼講解

一、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>

二、使用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="width: 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

相關文章
相關標籤/搜索