驗證碼在不少地方都會遇到,實現的方法和形式也有不少,主要的目的就是爲了安全,防止一些惡意的攻擊等。說實話那麼多年居然沒注意過這東西,原理很簡單,貼出來給你們作個參考。html
通常稍微有些經驗的程序員都不會再本身寫原生驗證碼生成了,由於各類強大的開源組件,足以解決咱們大部分的需求。可是,畢竟也是剛接觸這東西,還須要從原理入手的。java
項目效果圖:git
下面我就簡單介紹下原生和使用開源項目kaptcha生成驗證碼的兩種形式。程序員
效果:github
一、定義BufferedImage(圖像數據緩衝區)對象web
二、得到Graphics對象spring
三、隨機生成驗證碼字母或者數字數據庫
四、使用Graphics繪製圖片數組
五、記錄驗證碼信息到session或數據庫,以便校驗安全
五、ImageIO輸出圖片到客戶端
這裏我就不整合框架了,簡單用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的方式分別進行下介紹。
既然說到開源組件,必然功能是強大的,仍是先看效果圖!
數字字母組合
數字字母漢字組合
算數計算
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 |
一、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