验证码概述

为什么使用验证码?

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

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

使用Servlet实现验证码

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

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

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

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

  检验验证码是否正确:ValidateImageServlet

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

  验证的流程如下:

  生成验证码的ImageServlet:

 private static Random r = new Random();
private static char[] chs = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
private static final int NUMBER_OF_CHS = 4;
private static final int IMG_WIDTH = 65;
private static final int IMG_HEIGHT = 25; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { BufferedImage image = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB); // 实例化BufferedImage
Graphics g = image.getGraphics();
Color c = new Color(200, 200, 255); // 验证码图片的背景颜色
g.setColor(c);
g.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT); // 图片的边框 StringBuffer sb = new StringBuffer(); // 用于保存验证码字符串
int index; // 数组的下标
for (int i = 0; i < NUMBER_OF_CHS; i++) {
index = r.nextInt(chs.length); // 随机一个下标
g.setColor(new Color(r.nextInt(88), r.nextInt(210), r.nextInt(150))); // 随机一个颜色
g.drawString(chs[index] + "", 15 * i + 3, 18); // 画出字符
sb.append(chs[index]); // 验证码字符串
} request.getSession().setAttribute("piccode", sb.toString()); // 将验证码字符串保存到session中
ImageIO.write(image, "jpg", response.getOutputStream()); // 向页面输出图像
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
} }

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

 public class ValidateImageServlet extends HttpServlet {

     public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doPost(request, response);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { response.setContentType("text/html;charset=utf-8");
String picString = (String) request.getSession().getAttribute("piccode");
String checkCode = request.getParameter("verifyCode");
PrintWriter out = response.getWriter();
if (picString.toUpperCase().equals(checkCode.toUpperCase()))
out.println("验证码正确");
else
out.print("验证码错误!"); out.flush();
out.close();
} }

开源组件实现验证码

  Jcaptcha:

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

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

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

  web.xml的配置如下:

 <servlet>
<servlet-name>jcaptcha</servlet-name>
<servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
</servlet>
<!-- 处理表单提交的Servlet -->
<servlet>
<servlet-name>submit</servlet-name>
<servlet-class>org.gpf.servlet.SubmitActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jcaptcha</servlet-name>
<url-pattern>/jcaptcha.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>submit</servlet-name>
<url-pattern>/submit.action</url-pattern>
</servlet-mapping>

  表单提交的Servlet:

 package org.gpf.servlet;

 import java.io.IOException;

 import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet;
/**
* 图片验证码的captcha实现
* @author gaopengfei
* @date 2015-5-20 下午9:58:20
*/
public class SubmitActionServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException { String userCaptchaResponse = request.getParameter("japtcha");
boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse(request, userCaptchaResponse); response.setContentType("text/html;charset=utf-8");
if (captchaPassed)
response.getWriter().write("验证通过!");
else {
response.getWriter().write("验证失败!");
}
response.getWriter().write("<br/><a href='auth_code_captcha.jsp'>重新验证</a>");
}
}

  

  kaptcha:

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

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

  用于验证验证码的check.jsp

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

  配置图片显示的Servlet:

 <servlet>
<servlet-name>Kcaptcha</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Kcaptcha</servlet-name>
<url-pattern>/random.jpg</url-pattern>
</servlet-mapping>

  

Kaptcha的详细配置

 <servlet>
<servlet-name>Kcaptcha</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>边框颜色,white、black(默认)、blue等</description>
<param-name>kaptcha.border.color</param-name>
<param-value>green</param-value>
</init-param>
<init-param>
<description>边框厚度大于0</description>
<param-name>kaptcha.border.thickness</param-name>
<param-value>10</param-value>
</init-param> <!-- 图片宽高 -->
<init-param>
<description>图片宽度</description>
<param-name>kaptcha.image.width</param-name>
<param-value>200</param-value>
</init-param>
<init-param>
<description>图片高度</description>
<param-name>kaptcha.image.height</param-name>
<param-value>60</param-value>
</init-param> <!-- 图片样式 -->
<init-param>
<description>图片样式:水纹(WaterRipple)、鱼眼(FishEyeGimpy)、阴影(ShadowGimpy)</description>
<param-name>kaptcha.obscurificator.impl</param-name>
<param-value>com.google.code.kaptcha.impl.ShadowGimpy</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>yellow</param-value>
</init-param>
<init-param>
<description>背景颜色渐变,指定结束颜色</description>
<param-name>kaptcha.background.clear.to</param-name>
<param-value>red</param-value>
</init-param> <!-- 文本 -->
<init-param>
<description>文本集合,验证码文字从此集合中获取</description>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>0123456789</param-value>
</init-param>
<init-param>
<description>验证码长度</description>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>6</param-value>
</init-param>
<init-param>
<description>文字间隔</description>
<param-name>kaptcha.textproducer.char.space</param-name>
<param-value>2</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>字体大小</description>
<param-name>kaptcha.textproducer.font.size</param-name>
<param-value>40</param-value>
</init-param>
<init-param>
<description>字体颜色,white、black(默认)、blue等</description>
<param-name>kaptcha.textproducer.font.color</param-name>
<param-value>pink</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>图片实现类,可以重写这个类实现我们自己的图片</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>干扰实现类</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>255,0,0</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>
</servlet>
<servlet-mapping>
<servlet-name>Kcaptcha</servlet-name>
<url-pattern>/random.jpg</url-pattern>
</servlet-mapping>

  中文验证码

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

 /**
* 中文验证码的实现类
*/
public class ChineseTextCreator extends Configurable implements TextProducer { @Override
public String getText() { int length = getConfig().getTextProducerCharLength();
String finalWord = "", firstWord = "";
int tempInt = 0;
String[] array = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"a", "b", "c", "d", "e", "f" }; Random rand = new Random(); for (int i = 0; i < length; i++) {
switch (rand.nextInt(array.length)) {
case 1:
tempInt = rand.nextInt(26) + 65;
firstWord = String.valueOf((char) tempInt);
break;
case 2:
int r1,
r2,
r3,
r4;
String strH,
strL;// high&low
r1 = rand.nextInt(3) + 11; // 前闭后开[11,14)
if (r1 == 13) {
r2 = rand.nextInt(7);
} else {
r2 = rand.nextInt(16);
} r3 = rand.nextInt(6) + 10;
if (r3 == 10) {
r4 = rand.nextInt(15) + 1;
} else if (r3 == 15) {
r4 = rand.nextInt(15);
} else {
r4 = rand.nextInt(16);
} strH = array[r1] + array[r2];
strL = array[r3] + array[r4]; byte[] bytes = new byte[2];
bytes[0] = (byte) (Integer.parseInt(strH, 16));
bytes[1] = (byte) (Integer.parseInt(strL, 16)); firstWord = new String(bytes);
break;
default:
tempInt = rand.nextInt(10) + 48;
firstWord = String.valueOf((char) tempInt);
break;
}
finalWord += firstWord;
}
return finalWord;
}
}

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

 <init-param>
<description>文本实现类</description>
<param-name>kaptcha.textproducer.impl</param-name>
<param-value>ChineseTextCreator</param-value>
</init-param>

  算式验证码

实现步骤如下:

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

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

 public class MyKaptchaServlet extends HttpServlet implements Servlet{

     private Properties props;
private Producer kaptchaProducer;
private String sessionKeyValue; public MyKaptchaServlet() {
props = new Properties();
kaptchaProducer = null;
sessionKeyValue = null;
} public void init(ServletConfig conf) throws ServletException {
super.init(conf); ImageIO.setUseCache(false); Enumeration initParams = conf.getInitParameterNames();
while (initParams.hasMoreElements()) {
String key = (String) initParams.nextElement();
String value = conf.getInitParameter(key);
this.props.put(key, value);
} Config config = new Config(this.props);
this.kaptchaProducer = config.getProducerImpl();
this.sessionKeyValue = config.getSessionKey();
} public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setDateHeader("Expires", 0L); resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); resp.addHeader("Cache-Control", "post-check=0, pre-check=0"); resp.setHeader("Pragma", "no-cache"); resp.setContentType("image/jpeg"); String capText = this.kaptchaProducer.createText();
String s1 = capText.substring(0, 1); // 获取随机生成的第一个数字
String s2 = capText.substring(1, 2); // 由于web.xml中配置的验证码字符都是数字,不会发生数字格式化异常
int r = Integer.parseInt(s1) + Integer.parseInt(s2); req.getSession().setAttribute(this.sessionKeyValue, String.valueOf(r)); // 将结果存入session BufferedImage bi = this.kaptchaProducer.createImage(s1 + " + " + s2 + " = ?"); // 产生图片 ServletOutputStream out = resp.getOutputStream(); ImageIO.write(bi, "jpg", out);
try {
out.flush();
} finally {
out.close();
}
} }

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

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

Java实现验证码的制作的更多相关文章

  1. 【工具】java发送验证码邮件

    文章目录 前言 配置邮箱服务器 代码实现 发送随机验证码与验证 后记 前言 要实现 可以设置格式,附件,抄送等功能,就跟真人操控邮箱发送邮件一样的功能,或许比较难,博主没研究,博主暂时没用到那些功能, ...

  2. java识别验证码

    所需资源下载链接(资源免费,重在分享) Tesseract:http://download.csdn.net/detail/chenyangqi/9190667 jai_imageio-1.1-alp ...

  3. 【开发技术】Java生成验证码

    Java生成验证码 为了防止用户恶意,或者使用软件外挂提交一些内容,就得用验证码来阻止,虽然这个会影响用户体验,但为了避免一些问题很多网站都使用了验证码;今天下午参考文档弄了一个验证码,这里分享一下; ...

  4. 登陆时验证码的制作(asp.net)

    登陆时验证码的制作(asp.net) 1.显示样式: 2.新建一个页,Default2.aspx 3.在Page_load事件拷入如下代码 stringtmp = RndNum(4); HttpCoo ...

  5. 使用Java设计验证码生成程序

    我们来设计一个简单的验证码生成程序:验证码一个由4位的数字.字母随机组合而成图像,为了避免被光学字元识别(OCR,Optical Character Recognition)之类的程序识别出图片中的数 ...

  6. java图形验证码

    用java实现验证码的生成,以下代码是一个controller,可以直接使用 package org.jxnd.tongxuelu.controller; import java.awt.Color; ...

  7. java实现验证码功能

    java实现验证码功能 通过java代码实现验证码功能的一般思路: 一.通过java代码生成一张验证码的图片,将验证码的图片保存到项目中的指定文件中去,代码如下: package com.util; ...

  8. 工作笔记5.JAVA图片验证码

    本文主要内容为:利用JAVA图片制作验证码. 设计思路: 1.拷贝AuthImageServlet.class图片验证码 2.配置web.xml 3.JSP中,调用封装好的AuthImageServl ...

  9. java生成图片验证码(转)--封装生成图片验证码的工具类

    博客部分内容转载自 LonlySnow的博客:后台java 实现验证码生成 1.controller方法 @RequestMapping(value = "/verifycode/img&q ...

随机推荐

  1. centos 7安装 navicat

    下载地址: http://download.navicat.com/download/navicat111_mysql_en.tar.gz 下载后copy到指定安装文件夹 [hcr@localhost ...

  2. Struts2-Spring和Hibernate整合

    Struts作为MVC 2的Web框架,自推出以来不断受到开发者的追捧,得到广泛的应用.作为最成功的Web框架,Struts自然拥有众多的优点:MVC 2模型的使用.功能齐全的标志库(Tag Libr ...

  3. 批量部署 自动化之 - [pssh](转)

    并行执行命令工具简介 作为运维工程师来讲,机器数量到一定级别的时候,批量运维和管理机器就是一件费神的事情,还好有很多可以批量并行执行命令的工具,比如 pssh , python fabrictaoba ...

  4. C# Conditional特性避免 预处理命令泛滥使用

    //#define CONDITION1 #define CONDITION2 using System; using System.Diagnostics; class Test { static ...

  5. Ubuntu下开启mysql远程登陆权限

    在腾讯云上租了个云服务器,并且安装启动了mysql. 这时候用本地的mysql workbench去连接就会报错,提示无法成功连接. 其实这是因为没有开启账户的远程登陆权限.那么下面就开启一下: 1. ...

  6. 在云服务器上部署node.js服务器

    本文档介绍腾讯云·万象优图服务端nodejs的部署和集成,搭建一个nodejs+nginx为基础,对web端或者移动端提供http签名接口服务的例子程序.注意:本文档只是简单的示例,展示了服务端为终端 ...

  7. android UI 适配小节

    一.   像素密度表 像素密度表 比如UE 给了三张切图分别对应: mdpi,     xhdpi,     xxdpi 10 * 10,     20 * 20,     30 * 30 上面的值都 ...

  8. MAC 通过brew安装软件

    1.安装brew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/instal ...

  9. ui-router参数传递

    基本参数: ‘/user/:id' '/user/{id}' '/user/{id:int}' 使用正则表达式: '/user/{id:[0-9]{1,8}' '/user/{id:.*}' '/us ...

  10. springboot+springAOP实现数据库读写分离及数据库同步(MySQL)----最新可用2019-2-14

    原文:https://blog.csdn.net/wsbgmofo/article/details/79260896 1,数据源配置文件,如下 datasource.readSize=1spring. ...