热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java实现验证码的制作

验证码概述为什么使用验证码?验证码(CAPTCHA)是一种全自动程序。主要是为了区分“进行操作的是不是人”。如果没有验证码机制,将会导致以下的问题:对特定网站不断进行登录,破解密码
验证码概述

为什么使用验证码?

  验证码(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);    // 实例化BufferedImage
12             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 ) {
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         else
19             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>jcaptchaservlet-name>
 3     <servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServletservlet-class>
 4 servlet>
 5 
 6 <servlet>
 7     <servlet-name>submitservlet-name>
 8     <servlet-class>org.gpf.servlet.SubmitActionServletservlet-class>
 9 servlet>
10 <servlet-mapping>
11     <servlet-name>jcaptchaservlet-name>
12     <url-pattern>/jcaptcha.jpgurl-pattern>
13 servlet-mapping>
14 <servlet-mapping>
15     <servlet-name>submitservlet-name>
16     <url-pattern>/submit.actionurl-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 gaopengfei
14  * @date 2015-5-20 下午9:58:20
15  */
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("
重新验证"); 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("验证通过!
"); 9 else 10 out.print("验证失败!
"); 11 out.print("你输入的字符:" + myImageText + ",验证码字符:" + key); 12 %>

  配置图片显示的Servlet:

1 <servlet>
2     <servlet-name>Kcaptchaservlet-name>
3     <servlet-class>com.google.code.kaptcha.servlet.KaptchaServletservlet-class>
4 servlet>
5 <servlet-mapping>
6     <servlet-name>Kcaptchaservlet-name>
7     <url-pattern>/random.jpgurl-pattern>
8 servlet-mapping>

  技术分享

Kaptcha的详细配置

  1 <servlet>
  2     <servlet-name>Kcaptchaservlet-name>
  3     <servlet-class>com.google.code.kaptcha.servlet.KaptchaServletservlet-class>
  4     
  5     
  6     <init-param>
  7         <description>图片边框,yes(默认值)或者nodescription>
  8         <param-name>kaptcha.borderparam-name>
  9         <param-value>yesparam-value>
 10     init-param>
 11     <init-param>
 12         <description>边框颜色,white、black(默认)、blue等description>
 13         <param-name>kaptcha.border.colorparam-name>
 14         <param-value>greenparam-value>
 15     init-param>
 16     <init-param>
 17         <description>边框厚度大于0description>
 18         <param-name>kaptcha.border.thicknessparam-name>
 19         <param-value>10param-value>
 20     init-param>
 21     
 22     
 23     <init-param>
 24         <description>图片宽度description>
 25         <param-name>kaptcha.image.widthparam-name>
 26         <param-value>200param-value>
 27     init-param>
 28     <init-param>
 29         <description>图片高度description>
 30         <param-name>kaptcha.image.heightparam-name>
 31         <param-value>60param-value>
 32     init-param>
 33 
 34     
 35     <init-param>
 36         <description>图片样式:水纹(WaterRipple)、鱼眼(FishEyeGimpy)、阴影(ShadowGimpy)description>
 37         <param-name>kaptcha.obscurificator.implparam-name>
 38         <param-value>com.google.code.kaptcha.impl.ShadowGimpyparam-value>
 39     init-param>
 40     
 41     
 42     <init-param>
 43         <description>背景实现类description>
 44         <param-name>kaptcha.background.implparam-name>
 45         <param-value>com.google.code.kaptcha.impl.DefaultBackgroundparam-value>
 46     init-param>
 47     <init-param>
 48         <description>背景颜色渐变,指定开始颜色description>
 49         <param-name>kaptcha.background.clear.fromparam-name>
 50         <param-value>yellowparam-value>
 51     init-param>
 52     <init-param>
 53         <description>背景颜色渐变,指定结束颜色description>
 54         <param-name>kaptcha.background.clear.toparam-name>
 55         <param-value>redparam-value>
 56     init-param>
 57     
 58     
 59     <init-param>
 60         <description>文本集合,验证码文字从此集合中获取description>
 61         <param-name>kaptcha.textproducer.char.stringparam-name>
 62         <param-value>0123456789param-value>
 63     init-param>
 64     <init-param>
 65         <description>验证码长度description>
 66         <param-name>kaptcha.textproducer.char.lengthparam-name>
 67         <param-value>6param-value>
 68     init-param>
 69     <init-param>
 70         <description>文字间隔description>
 71         <param-name>kaptcha.textproducer.char.spaceparam-name>
 72         <param-value>2param-value>
 73     init-param>
 74     
 75     <init-param>
 76         <description>字体Arial,Courierdescription>
 77         <param-name>kaptcha.textproducer.font.namesparam-name>
 78         <param-value>Arial,Courierparam-value>
 79     init-param>
 80     <init-param>
 81         <description>字体大小description>
 82         <param-name>kaptcha.textproducer.font.sizeparam-name>
 83         <param-value>40param-value>
 84     init-param>
 85     <init-param>
 86         <description>字体颜色,white、black(默认)、blue等description>
 87         <param-name>kaptcha.textproducer.font.colorparam-name>
 88         <param-value>pinkparam-value>
 89     init-param>
 90 
 91     <init-param>
 92         <description>文字渲染器description>
 93         <param-name>kaptcha.word.implparam-name>
 94         <param-value>com.google.code.kaptcha.text.impl.DefaultWordRendererparam-value>
 95     init-param>
 96 
 97     
 98     <init-param>
 99         <description>图片实现类,可以重写这个类实现我们自己的图片description>
100         <param-name>kaptcha.producer.implparam-name>
101         <param-value>com.google.code.kaptcha.impl.DefaultKaptchaparam-value>
102     init-param>
103     <init-param>
104         <description>文本实现类description>
105         <param-name>kaptcha.textproducer.implparam-name>
106         <param-value>com.google.code.kaptcha.text.impl.DefaultTextCreatorparam-value>
107     init-param>
108     
109     
110     <init-param>
111         <description>干扰实现类description>
112         <param-name>kaptcha.noise.implparam-name>
113         <param-value>com.google.code.kaptcha.impl.DefaultNoiseparam-value>
114     init-param>
115     <init-param>
116         <description>干扰颜色,合法值r,g,b或者white、black、bluedescription>
117         <param-name>kaptcha.noise.colorparam-name>
118         <param-value>255,0,0param-value>
119     init-param>
120     
121     <init-param>
122         <description>session中存放验证码的key键description>
123         <param-name>kaptcha.session.keyparam-name>
124         <param-value>KAPTCHA_SESSION_KEYparam-value>
125     init-param>
126 servlet>
127 <servlet-mapping>
128     <servlet-name>Kcaptchaservlet-name>
129     <url-pattern>/random.jpgurl-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 ) {
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&low
30                 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.implparam-name>
4     <param-value>ChineseTextCreatorparam-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));    // 将结果存入session
48 
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>Kcaptchaservlet-name>
 2     <servlet-class>MyKaptchaServletservlet-class>
 3 <init-param>
 4         <description>文本集合description>
 5         <param-name>kaptcha.textproducer.char.stringparam-name>
 6         <param-value>0123456789param-value>
 7     init-param>
 8     <init-param>
 9     <description>验证码长度description>
10     <param-name>kaptcha.textproducer.char.lengthparam-name>
11     <param-value>8param-value>
12 init-param>

技术分享

Java实现验证码的制作


推荐阅读
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • MySQL中枚举类型的所有可能值获取方法
    本文介绍了一种在MySQL数据库中查询枚举(ENUM)类型字段所有可能取值的方法,帮助开发者更好地理解和利用这一数据类型。 ... [详细]
  • Vue 2 中解决页面刷新和按钮跳转导致导航栏样式失效的问题
    本文介绍了如何通过配置路由的 meta 字段,确保 Vue 2 项目中的导航栏在页面刷新或内部按钮跳转时,始终保持正确的 active 样式。具体实现方法包括设置路由的 meta 属性,并在 HTML 模板中动态绑定类名。 ... [详细]
  • 本文探讨了如何通过最小生成树(MST)来计算严格次小生成树。在处理过程中,需特别注意所有边权重相等的情况,以避免错误。我们首先构建最小生成树,然后枚举每条非树边,检查其是否能形成更优的次小生成树。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
  • 几何画板展示电场线与等势面的交互关系
    几何画板是一款功能强大的物理教学软件,具备丰富的绘图和度量工具。它不仅能够模拟物理实验过程,还能通过定量分析揭示物理现象背后的规律,尤其适用于难以在实际实验中展示的内容。本文将介绍如何使用几何画板演示电场线与等势面之间的关系。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文介绍如何在应用程序中使用文本输入框创建密码输入框,并通过设置掩码来隐藏用户输入的内容。我们将详细解释代码实现,并提供专业的补充说明。 ... [详细]
author-avatar
壹花壹浄土
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有