Java实现验证码的制作

来源:互联网 发布:centos安装hadoop2.6 编辑:程序博客网 时间:2024/06/06 07:19

验证码概述

为什么使用验证码?

  验证码(CAPTCHA)是一种全自动程序。主要是为了区分“进行操作的是不是人”。如果没有验证码机制,将会导致以下的问题:

  • 对特定网站不断进行登录,破解密码;
  • 对某个网站创建账户;
  • 对某个网站提交垃圾数据(灌水贴);
  • 对某个网站进行刷票。

 

使用Servlet实现验证码

  一个验证码包含两个部分:图片和输入框。

复制代码
 1 <script type="text/javascript"> 2     function reloadCode(){ 3         var time = new Date(); 4         // 给URL传递参数可以清空浏览器的缓存,让浏览器认为这是一个新的请求 5         document.getElementById('safecode').src = '<%=request.getContextPath()%>/servlet/ImageServlet?d=' + time; 6     } 7 </script>     8  9 <form action="<%=request.getContextPath()%>/servlet/ValidateImageServlet"method="post">10         验证码:<img src="<%=request.getContextPath()%>/servlet/ImageServlet" alt="验证码" id="safecode">11     <input type="text" id="verifyCode" name="verifyCode" size="6" />12     <a href="javascript:reloadCode();">看不清楚</a><br>13     <input type="submit" value="登录" />14 </form>
复制代码

  我们用ImageServlet实时生成图片。生成图片所需要的步骤如下:

1 定义BufferedImage对象2 获得Graphics对象3 听过Random类产生随机验证码信息4 使用Graphics绘制图片5 记录验证码信息到session中6 使用ImageIO输出图片

  检验验证码是否正确:ValidateImageServlet

1 获取页面的验证码2 获取session中保存的验证码3 比较验证码4 返回校验结果

  验证的流程如下:

  生成验证码的ImageServlet:

复制代码
 1 private static Random r = new Random(); 2     private static char[] chs = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); 3     private static final int NUMBER_OF_CHS = 4; 4     private static final int IMG_WIDTH = 65; 5     private static final int IMG_HEIGHT = 25; 6      7      8     public void doGet(HttpServletRequest request, HttpServletResponse response) 9             throws ServletException, IOException {10 11             BufferedImage image = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB);    // 实例化BufferedImage12             Graphics g = image.getGraphics();13             Color c = new Color(200, 200, 255);                                             // 验证码图片的背景颜色                                        14             g.setColor(c);15             g.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);                                        // 图片的边框16             17             StringBuffer sb = new StringBuffer();                                           // 用于保存验证码字符串18             int index;                                                                      // 数组的下标19             for (int i = 0; i < NUMBER_OF_CHS; i++) {20                 index = r.nextInt(chs.length);                                              // 随机一个下标21                 g.setColor(new Color(r.nextInt(88), r.nextInt(210), r.nextInt(150)));       // 随机一个颜色22                 g.drawString(chs[index] + "", 15 * i + 3, 18);                              // 画出字符23                 sb.append(chs[index]);                                                      // 验证码字符串24             }25             26             request.getSession().setAttribute("piccode", sb.toString());                    // 将验证码字符串保存到session中27             ImageIO.write(image, "jpg", response.getOutputStream());                        // 向页面输出图像28     }29 30     public void doPost(HttpServletRequest request, HttpServletResponse response)31             throws ServletException, IOException {32         doGet(request, response);33     }34 35 }
复制代码

  进行验证码图片验证的Servlet:

复制代码
 1 public class ValidateImageServlet extends HttpServlet { 2  3     public void doGet(HttpServletRequest request, HttpServletResponse response) 4             throws ServletException, IOException { 5          6         doPost(request, response); 7     } 8  9     public void doPost(HttpServletRequest request, HttpServletResponse response)10             throws ServletException, IOException {11 12         response.setContentType("text/html;charset=utf-8");13         String picString = (String) request.getSession().getAttribute("piccode");14         String checkCode = request.getParameter("verifyCode");15         PrintWriter out = response.getWriter();16         if (picString.toUpperCase().equals(checkCode.toUpperCase()))17             out.println("验证码正确");18         else19             out.print("验证码错误!");20         21         out.flush();22         out.close();23     }24 25 }
复制代码

 开源组件实现验证码

  Jcaptcha:

  一个用来生成图形验证码的开源组件,可以产生多种形式的验证码。可以与Spring组合使用。需要导入的jar包如下:

  用于展示验证码的auth_code_captcha.jsp如下:

1 <form action="submit.action" method="post">2      <img src="jcaptcha.jpg" /> <input type="text" name="japtcha" value="" />3      <input type="submit"/>4 </form>

  web.xml的配置如下:

复制代码
 1 <servlet> 2     <servlet-name>jcaptcha</servlet-name> 3     <servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class> 4 </servlet> 5 <!-- 处理表单提交的Servlet --> 6 <servlet> 7     <servlet-name>submit</servlet-name> 8     <servlet-class>org.gpf.servlet.SubmitActionServlet</servlet-class> 9 </servlet>10 <servlet-mapping>11     <servlet-name>jcaptcha</servlet-name>12     <url-pattern>/jcaptcha.jpg</url-pattern>13 </servlet-mapping>14 <servlet-mapping>15     <servlet-name>submit</servlet-name>16     <url-pattern>/submit.action</url-pattern>17 </servlet-mapping>
复制代码

  表单提交的Servlet:

复制代码
 1 package org.gpf.servlet; 2  3 import java.io.IOException; 4  5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 import com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet;11 /**12  * 图片验证码的captcha实现13  * @author gaopengfei14  * @date 2015-5-20 下午9:58:2015  */16 public class SubmitActionServlet extends HttpServlet {17     18     private static final long serialVersionUID = 1L;19 20     protected void doPost(HttpServletRequest request,21             HttpServletResponse response) throws ServletException, IOException {22         23         String userCaptchaResponse = request.getParameter("japtcha");24         boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse(request, userCaptchaResponse);25         26         response.setContentType("text/html;charset=utf-8");27         if (captchaPassed)28             response.getWriter().write("验证通过!");29         else {30             response.getWriter().write("验证失败!");31         }32         response.getWriter().write("<br/><a href='auth_code_captcha.jsp'>重新验证</a>");33     }34 }
复制代码

  

  kaptcha:

  它是可以配置的,也可以生成各种样式的验证码。如下是其简单应用:用于显示验证码的index.jsp

1 <img alt="验证码图片" src="random.jpg">2 <form action="check.jsp" method="post">3     <input type="text" name="imageText">4     <input type="submit" value="验证">5 </form>

  用于验证验证码的check.jsp

复制代码
 1 <%@ page import="com.google.code.kaptcha.Constants" %> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 <% 4     String myImageText = request.getParameter("imageText"); 5     String key = (String)request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); 6      7     if(!myImageText.isEmpty() && myImageText.equals(key)) 8         out.print("验证通过!<br />"); 9     else10         out.print("验证失败!<br />");    11     out.print("你输入的字符:" + myImageText + ",验证码字符:" + key);    12  %>
复制代码

  配置图片显示的Servlet:

复制代码
1 <servlet>2     <servlet-name>Kcaptcha</servlet-name>3     <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>4 </servlet>5 <servlet-mapping>6     <servlet-name>Kcaptcha</servlet-name>7     <url-pattern>/random.jpg</url-pattern>8 </servlet-mapping>
复制代码

  

Kaptcha的详细配置

复制代码
  1 <servlet>  2     <servlet-name>Kcaptcha</servlet-name>  3     <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>  4       5     <!-- 边框 -->  6     <init-param>  7         <description>图片边框,yes(默认值)或者no</description>  8         <param-name>kaptcha.border</param-name>  9         <param-value>yes</param-value> 10     </init-param> 11     <init-param> 12         <description>边框颜色,white、black(默认)、blue等</description> 13         <param-name>kaptcha.border.color</param-name> 14         <param-value>green</param-value> 15     </init-param> 16     <init-param> 17         <description>边框厚度大于0</description> 18         <param-name>kaptcha.border.thickness</param-name> 19         <param-value>10</param-value> 20     </init-param> 21      22     <!-- 图片宽高 --> 23     <init-param> 24         <description>图片宽度</description> 25         <param-name>kaptcha.image.width</param-name> 26         <param-value>200</param-value> 27     </init-param> 28     <init-param> 29         <description>图片高度</description> 30         <param-name>kaptcha.image.height</param-name> 31         <param-value>60</param-value> 32     </init-param> 33  34     <!-- 图片样式 --> 35     <init-param> 36         <description>图片样式:水纹(WaterRipple)、鱼眼(FishEyeGimpy)、阴影(ShadowGimpy)</description> 37         <param-name>kaptcha.obscurificator.impl</param-name> 38         <param-value>com.google.code.kaptcha.impl.ShadowGimpy</param-value> 39     </init-param> 40      41     <!-- 背景 --> 42     <init-param> 43         <description>背景实现类</description> 44         <param-name>kaptcha.background.impl</param-name> 45         <param-value>com.google.code.kaptcha.impl.DefaultBackground</param-value> 46     </init-param> 47     <init-param> 48         <description>背景颜色渐变,指定开始颜色</description> 49         <param-name>kaptcha.background.clear.from</param-name> 50         <param-value>yellow</param-value> 51     </init-param> 52     <init-param> 53         <description>背景颜色渐变,指定结束颜色</description> 54         <param-name>kaptcha.background.clear.to</param-name> 55         <param-value>red</param-value> 56     </init-param> 57      58     <!-- 文本 --> 59     <init-param> 60         <description>文本集合,验证码文字从此集合中获取</description> 61         <param-name>kaptcha.textproducer.char.string</param-name> 62         <param-value>0123456789</param-value> 63     </init-param> 64     <init-param> 65         <description>验证码长度</description> 66         <param-name>kaptcha.textproducer.char.length</param-name> 67         <param-value>6</param-value> 68     </init-param> 69     <init-param> 70         <description>文字间隔</description> 71         <param-name>kaptcha.textproducer.char.space</param-name> 72         <param-value>2</param-value> 73     </init-param> 74     <!-- 字体 --> 75     <init-param> 76         <description>字体Arial,Courier</description> 77         <param-name>kaptcha.textproducer.font.names</param-name> 78         <param-value>Arial,Courier</param-value> 79     </init-param> 80     <init-param> 81         <description>字体大小</description> 82         <param-name>kaptcha.textproducer.font.size</param-name> 83         <param-value>40</param-value> 84     </init-param> 85     <init-param> 86         <description>字体颜色,white、black(默认)、blue等</description> 87         <param-name>kaptcha.textproducer.font.color</param-name> 88         <param-value>pink</param-value> 89     </init-param> 90  91     <init-param> 92         <description>文字渲染器</description> 93         <param-name>kaptcha.word.impl</param-name> 94         <param-value>com.google.code.kaptcha.text.impl.DefaultWordRenderer</param-value> 95     </init-param> 96  97     <!-- 图片和文本的实现类 --> 98     <init-param> 99         <description>图片实现类,可以重写这个类实现我们自己的图片</description>100         <param-name>kaptcha.producer.impl</param-name>101         <param-value>com.google.code.kaptcha.impl.DefaultKaptcha</param-value>102     </init-param>103     <init-param>104         <description>文本实现类</description>105         <param-name>kaptcha.textproducer.impl</param-name>106         <param-value>com.google.code.kaptcha.text.impl.DefaultTextCreator</param-value>107     </init-param>108     109     <!-- 干扰 -->110     <init-param>111         <description>干扰实现类</description>112         <param-name>kaptcha.noise.impl</param-name>113         <param-value>com.google.code.kaptcha.impl.DefaultNoise</param-value>114     </init-param>115     <init-param>116         <description>干扰颜色,合法值r,g,b或者white、black、blue</description>117         <param-name>kaptcha.noise.color</param-name>118         <param-value>255,0,0</param-value>119     </init-param>120     121     <init-param>122         <description>session中存放验证码的key键</description>123         <param-name>kaptcha.session.key</param-name>124         <param-value>KAPTCHA_SESSION_KEY</param-value>125     </init-param>126 </servlet>127 <servlet-mapping>128     <servlet-name>Kcaptcha</servlet-name>129     <url-pattern>/random.jpg</url-pattern>130 </servlet-mapping>
复制代码

  中文验证码

  查看前面的配置发现验证码字符的生成主要依靠的是kaptcha.textproducer.impl这个文本实现类,查看com.google.code.kaptcha.text.impl.DefaultTextCreator的源码,发现了它继承自 Configurable并实现了TextProducer接口。我们可以仿照它自定义我们自己的验证码中的文本生成器:

复制代码
 1 /** 2  * 中文验证码的实现类 3  */ 4 public class ChineseTextCreator extends Configurable implements TextProducer { 5  6     @Override 7     public String getText() { 8  9         int length = getConfig().getTextProducerCharLength();10         String finalWord = "", firstWord = "";11         int tempInt = 0;12         String[] array = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",13                 "a", "b", "c", "d", "e", "f" };14 15         Random rand = new Random();16 17         for (int i = 0; i < length; i++) {18             switch (rand.nextInt(array.length)) {19             case 1:20                 tempInt = rand.nextInt(26) + 65;21                 firstWord = String.valueOf((char) tempInt);22                 break;23             case 2:24                 int r1,25                 r2,26                 r3,27                 r4;28                 String strH,29                 strL;// high&low30                 r1 = rand.nextInt(3) + 11; // 前闭后开[11,14)31                 if (r1 == 13) {32                     r2 = rand.nextInt(7);33                 } else {34                     r2 = rand.nextInt(16);35                 }36 37                 r3 = rand.nextInt(6) + 10;38                 if (r3 == 10) {39                     r4 = rand.nextInt(15) + 1;40                 } else if (r3 == 15) {41                     r4 = rand.nextInt(15);42                 } else {43                     r4 = rand.nextInt(16);44                 }45 46                 strH = array[r1] + array[r2];47                 strL = array[r3] + array[r4];48 49                 byte[] bytes = new byte[2];50                 bytes[0] = (byte) (Integer.parseInt(strH, 16));51                 bytes[1] = (byte) (Integer.parseInt(strL, 16));52 53                 firstWord = new String(bytes);54                 break;55             default:56                 tempInt = rand.nextInt(10) + 48;57                 firstWord = String.valueOf((char) tempInt);58                 break;59             }60             finalWord += firstWord;61         }62         return finalWord;63     }64 }
复制代码

  只需要在web.xml中将初始化参数由默认的文本实现类改成我们自己的实现类:

1 <init-param>2     <description>文本实现类</description>3     <param-name>kaptcha.textproducer.impl</param-name>4     <param-value>ChineseTextCreator</param-value>5 </init-param>

  算式验证码

实现步骤如下:

  • 获取随机的数值将结果相加
  • 将计算公式写入到验证码图片
  • 将相加的结果放入到session中

因此,我们需要重写KaptchaServlet这个用于生成验证码的Servlet。

复制代码
 1 public class MyKaptchaServlet extends HttpServlet implements Servlet{ 2      3     private Properties props; 4     private Producer kaptchaProducer; 5     private String sessionKeyValue; 6      7     public MyKaptchaServlet() { 8          props = new Properties(); 9          kaptchaProducer = null;10          sessionKeyValue = null;11     }12     13     public void init(ServletConfig conf) throws ServletException {14         super.init(conf);15 16         ImageIO.setUseCache(false);17 18         Enumeration initParams = conf.getInitParameterNames();19         while (initParams.hasMoreElements()) {20             String key = (String) initParams.nextElement();21             String value = conf.getInitParameter(key);22             this.props.put(key, value);23         }24 25         Config config = new Config(this.props);26         this.kaptchaProducer = config.getProducerImpl();27         this.sessionKeyValue = config.getSessionKey();28     }29 30     public void doGet(HttpServletRequest req, HttpServletResponse resp)31             throws ServletException, IOException {32         resp.setDateHeader("Expires", 0L);33 34         resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");35 36         resp.addHeader("Cache-Control", "post-check=0, pre-check=0");37 38         resp.setHeader("Pragma", "no-cache");39 40         resp.setContentType("image/jpeg");41 42         String capText = this.kaptchaProducer.createText();43         String s1 = capText.substring(0, 1);    // 获取随机生成的第一个数字44         String s2 = capText.substring(1, 2);    // 由于web.xml中配置的验证码字符都是数字,不会发生数字格式化异常45         int r = Integer.parseInt(s1) + Integer.parseInt(s2);46 47         req.getSession().setAttribute(this.sessionKeyValue, String.valueOf(r));    // 将结果存入session48 49         BufferedImage bi = this.kaptchaProducer.createImage(s1 + " + " + s2 + " = ?"); // 产生图片50 51         ServletOutputStream out = resp.getOutputStream();52 53         ImageIO.write(bi, "jpg", out);54         try {55             out.flush();56         } finally {57             out.close();58         }59     }60 61 }
复制代码

  在web.xml中有2点需要注意:

  1. 验证码文本只能是0~9这10个数字;
  2. 验证码的长度是2(写多了也只会取出前2个随机数,写少了会抛出数字格式化异常)。
复制代码
 1 <servlet-name>Kcaptcha</servlet-name> 2     <servlet-class>MyKaptchaServlet</servlet-class> 3 <init-param> 4         <description>文本集合</description> 5         <param-name>kaptcha.textproducer.char.string</param-name> 6         <param-value>0123456789</param-value> 7     </init-param> 8     <init-param> 9     <description>验证码长度</description>10     <param-name>kaptcha.textproducer.char.length</param-name>11     <param-value>8</param-value>12 </init-param>
复制代码

原创粉丝点击