说起验证码,绝壁是个让人蛋疼的问题,特别是节假日在12306上面抢票的时候遇到的外星系验证码,大大降低了用户的体验度!
可是还是要知道验证码为什么存在,其作用是什么!
字母数字组合、加减法、中英文、算式加减法……
验证码降低了用户体验度,但是为什么存在呢???
如果没有验证码:
1) 对特定用户不断登录破解密码
2) 对某个网站创建账户
3) 对某个网站提交垃圾数据
4) 都某个网站刷票
如果存在验证码:
只有人亲自识别验证码,输入验证码内容,才能登录、发评论等等,防止计算机破解自动登录发灌水帖等;通过验证码来区分人和计算机;
验证码包含两部分:输入框和显示验证码的图片;
一般验证机制如下图:
可是,显示验证码的图片是如何产生的呢?
1) 手工生成的验证码比较简单,用到的类有
2) BufferedImage图像数据缓冲区
3) Graphics绘制图片
4) Color获取颜色
5) Random生成随机数
6) ImageIO输出图片
ImageServlet类:
package hdu.terence;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class ImageServlet extendsHttpServlet {
publicImageServlet() {
super();
}
publicvoid destroy() {
super.destroy();
}
publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
BufferedImagebi=new BufferedImage(68,22,BufferedImage.TYPE_INT_RGB);
Graphicsg=bi.getGraphics();
Colorc=new Color(200,150,255);
g.setColor(c);
g.fillRect(0,0, 68, 22);
char[]ch="WQERTYUIOPASDFG127890HJKLZ3456XCVBNMmnbvcxzkjhgfdsaqwertyuiop".toCharArray();
Randomr=new Random();
intlen=ch.length,index;
StringBuffersb=new StringBuffer();//用于保存图片
for(inti=0;i<4;i++)
{
index=r.nextInt(len);
g.setColor(newColor(r.nextInt(88),r.nextInt(188),r.nextInt(255)));
g.drawString(ch[index]+"",(i*15)+3, 18);
sb.append(ch[index]);
}
request.getSession().setAttribute("verifyCode",sb.toString());
ImageIO.write(bi,"JPG", response.getOutputStream());
}
publicvoid doPost(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
}
publicvoid init() throws ServletException {
}
}
LoginServlet类:
package hdu.terence;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class LoginServlet extendsHttpServlet {
publicLoginServlet() {
super();
}
publicvoid destroy() {
}
publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
response.setContentType("text/html;charset=gbk");
StringverifyCode=(String) request.getSession().getAttribute("verifyCode");
StringcheckCode=request.getParameter("checkCode");
verifyCode=verifyCode.toUpperCase();
checkCode=checkCode.toUpperCase();
PrintWriterout=response.getWriter();
if(checkCode.equals(verifyCode))
{
out.println("niece!验证码输入正确!");
}
else
{
out.println("你似不似撒?验证码都能输入错误!!!!!!");
}
out.flush();
out.close();
}
publicvoid doPost(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
}
publicvoid init() throws ServletException { }
}
JSP:
结果:
Kaptcha:这个工具是可配置的,可以生成各种花式的验证码,可通过配置参数增加机器识别难度。
准备步骤:
1) 下载kaptcha-2.3.jar(点击下载kaptcha-2.3.jar)
2) 将jar包导入项目,添加到路径
3) 编写页面
4) 配置web.xml
5) 启动项目
Step1 JSP:
输入验证码:
看不清,重换一张
src:连接到后台生成的randomcode.jpg;
Step2 在web.xml中添加映射配置:
kaptcha
/randomcode.jpg
Step3 增加配置参数,防止机器识别图片;
可配置的参数如下:
-
图片边框,合法值:yes , no
kaptcha.border
yes
-
边框颜色,合法值: r,g,b (and optional alpha) 或者white,black,blue.
kaptcha.border.color
red
-
边框厚度,合法值:>0
kaptcha.border.thickness
2
-
图片宽 200
kaptcha.image.width
150
-
图片高 50
kaptcha.image.height
50
-
图片实现类
kaptcha.producer.impl
com.google.code.kaptcha.impl.DefaultKaptcha
-
不用文本实现:com.google.code.kaptcha.impl.DifaultTextCreator用文本实现:则用自己重写的中文类(内含算法)ChineseTextCheck.ChineseTextCode
kaptcha.textproducer.impl
ChineseTextCheck.ChineseTextCode
-
文本集合,验证码值从此集合中获取
kaptcha.textproducer.char.string
qwertys1zcmd2345s67g890
-
-
-
验证码长度 5
kaptcha.textproducer.char.length
5
-
字体Arial, Courier
kaptcha.textproducer.font.names
Arial, Courier
-
字体大小 40px.
kaptcha.textproducer.font.size
30
-
字体颜色,合法值: r,g,b 或者 white,black,blue.
kaptcha.textproducer.font.color
black
-
文字间隔 2
kaptcha.textproducer.char.space
2
-
干扰实现类
kaptcha.noise.impl
-
-
com.google.code.kaptcha.impl.DefaultNoise
-
干扰颜色,合法值: r,g,b 或者 white,black,blue.
kaptcha.noise.color
blue
-
图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple鱼眼com.google.code.kaptcha.impl.FishEyeGimpy阴影com.google.code.kaptcha.impl.ShadowGimpy
kaptcha.obscurificator.impl
com.google.code.kaptcha.impl.FishEyeGimpy
-
背景实现类
kaptcha.background.impl
com.google.code.kaptcha.impl.DefaultBackground
-
背景颜色渐变,开始颜色
kaptcha.background.clear.from
red
-
背景颜色渐变,结束颜色
kaptcha.background.clear.to
white
-
文字渲染器
kaptcha.word.impl
com.google.code.kaptcha.text.impl.DefaultWordRenderer
-
session中存放验证码的key键
kaptcha.session.key
KAPTCHA_SESSION_KEY
-
The date the kaptcha is generatedis put into the HttpSession. This is the key value for that item in thesession.
kaptcha.session.date
KAPTCHA_SESSION_DATE
Step 4 结果
Step1 重写配置文件里面的TextProducer类
import java.util.Random;
import com.google.code.kaptcha.text.TextProducer;
importcom.google.code.kaptcha.util.Configurable;
public class ChineseTextCode extendsConfigurable implements TextProducer {
/*
* 中文验证码(non-Javadoc)
* 粘贴以下算法重写文本实现类
* @see com.google.code.kaptcha.text.TextProducer#getText()
*/
publicString getText() {
intlength = getConfig().getTextProducerCharLength();
StringfinalWord = "", firstWord = "";
inttempInt = 0;
String[]array = { "0", "1", "2", "3","4", "5", "6", "7", "8","9",
"a","b", "c", "d", "e", "f" };
Randomrand = new Random();
for(int i = 0; i < length; i++) {
switch(rand.nextInt(array.length)) {
case1:
tempInt= rand.nextInt(26) + 65;
firstWord= String.valueOf((char) tempInt);
break;
case2:
intr1,
r2,
r3,
r4;
StringstrH,
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;
}
returnfinalWord;
}
publicString getText1() {
intlength = getConfig().getTextProducerCharLength();
//char[]charS = getConfig().getTextProducerCharString();
String[]s = new String[]{"我","是","阿","S","靖","卡","哥","滚","蛋","呸"};
Randomrand = new Random();
StringBuffersb = new StringBuffer();
for(inti = 0; i < length; i++){
intind =rand.nextInt(s.length);
sb.append(s[ind]);
}
returnsb.toString();
}
}
Step2 然后修改配置文件web.xml
文本实现类
kaptcha.textproducer.impl
ChineseTextCheck.ChineseTextCode
Step 3 结果
以重写Servlet的方式实现算式验证码
步骤:
1) 获取随机数值,结果相加
2) 将计算公式写到图片上
3) 将相加结果保存到session中
4) 依此为目标重写KapthaServlet类
Step1 重写KaptchaServlet
package formula;
import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.util.Config;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
import javax.imageio.ImageIO;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class KaptchaServlet extendsHttpServlet implements Servlet {
privateProperties props;
privateProducer kaptchaProducer;
privateString sessionKeyValue;
publicKaptchaServlet() {
this.props= new Properties();
this.kaptchaProducer= null;
this.sessionKeyValue= null;
}
publicvoid init(ServletConfig conf) throws ServletException {
super.init(conf);
ImageIO.setUseCache(false);
EnumerationinitParams = conf.getInitParameterNames();
while(initParams.hasMoreElements()) {
Stringkey = (String) initParams.nextElement();
Stringvalue = conf.getInitParameter(key);
this.props.put(key,value);
}
Configconfig = new Config(this.props);
this.kaptchaProducer= config.getProducerImpl();
this.sessionKeyValue= config.getSessionKey();
}
publicvoid doGet(HttpServletRequest req, HttpServletResponse resp)
throwsServletException, 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");
StringcapText = this.kaptchaProducer.createText();
Strings1 = capText.substring(0, 1);
Strings2 = capText.substring(1, 2);
intr = Integer.valueOf(s1).intValue() + Integer.valueOf(s2).intValue();
req.getSession().setAttribute(this.sessionKeyValue,String.valueOf(r));
BufferedImagebi = this.kaptchaProducer.createImage(s1+"+"+s2+"=?");
ServletOutputStreamout = resp.getOutputStream();
ImageIO.write(bi,"jpg", out);
try{
out.flush();
}finally {
out.close();
}
}
}
Step2 配置web.xml
kaptcha
文字、数字英文方式:com.google.code.kaptcha.servlet.KaptchaServlet
算式:使用自己重写的类:formula.KaptchaServlet
formula.KaptchaServlet
上述中formula.KaptchaServlet是指自己在formula包下重写的KaptchaServlet类。
Step3 结果