验证基础
一.什么是验证码及验证码的作用
验证码为全自动区分计算机和人类的图灵测试的缩写。是一种区分用户还是计算机的全自动程序,这个问题可以由计算机生成并进行判断,但是只有人类才可以解答。可以防止恶意破解密码,刷票,论坛灌水,有效防止某个黑客对某一个特定注册用户限定程序暴力破解方式进行不断登陆。
二.图文验证的原理
在servlet中随机生成一个指定位置的验证码,一般是四位或者六位。然后把该验证码保存到session中,再通过Java绘制类图以图片的形式输出该验证码。为了增加验证码的安全级别,可以输出图片的同时输出干扰线,最后在用户提交数据的时候,在服务器将用户提交的验证码和Session保存的验证码进行比较。
三.验证码所需要的技术
因为验证码中的文字,数字,应该是可变的,故要用到随机生成技术。
如果验证码中包含数字,则要用到数字生成技术。
可以使用Ajax技术实现局部刷新
可以使用图片的缩放和旋转技术
随机绘制干扰线,可以是直线,折线
如果考虑到验证码的安全性,可以使用MD5加密
下面是一个简单的demo,和截图:
1.编写生成英文字母,数字,汉字,随机生成的Servlet类,源码如下:
package com.servlet;import java.awt.BasicStroke;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.geom.AffineTransform;import java.awt.geom.Line2D;import java.awt.image.BufferedImage;import java.io.IOException;import java.util.Random;import javax.imageio.ImageIO;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;/** * @author :辰 * 创建时间:2017-3-16 下午2:41:41 * */public class PictureCheckCode extends HttpServlet { private static final long serialVersionUID = 1L; public PictureCheckCode() { super(); } public void destroy() { super.destroy(); } public void init() throws ServletException { super.init(); } public Color getRandColor(int s,int e){ Random random=new Random (); if(s>255) s=255; if(e>255) e=255; int r,g,b; r=s+random.nextInt(e-s); g=s+random.nextInt(e-s); b=s+random.nextInt(e-s); return new Color(r,g,b); } @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "No-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/jpeg"); int width=86,height=22; BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); Graphics g=image.getGraphics(); Graphics2D g2d=(Graphics2D)g; Random random=new Random(); Font mfont=new Font("楷体",Font.BOLD,16); g.setColor(getRandColor(200,250)); g.fillRect(0, 0, width, height); g.setFont(mfont); g.setColor(getRandColor(180,200)); for(int i=0;i<100;i++){ int x=random.nextInt(width-1); int y=random.nextInt(height-1); int x1=random.nextInt(6)+1; int y1=random.nextInt(12)+1; BasicStroke bs=new BasicStroke(2f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL); Line2D line=new Line2D.Double(x,y,x+x1,y+y1); g2d.setStroke(bs); g2d.draw(line); } String sRand=""; String ctmp=""; int itmp=0; for(int i=0;i<4;i++){ switch(random.nextInt(3)){ case 1: itmp=random.nextInt(26)+65; ctmp=String.valueOf((char)itmp); break; case 2: String[] rBase={"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"}; int r1=random.nextInt(3)+11; String str_r1=rBase[r1]; int r2; if(r1==13){ r2=random.nextInt(7); }else{ r2=random.nextInt(16); } String str_r2=rBase[r2]; int r3=random.nextInt(6)+10; String str_r3=rBase[r3]; int r4; if(r3==10){ r4=random.nextInt(15)+1; }else if(r3==15){ r4=random.nextInt(15); }else{ r4=random.nextInt(16); } String str_r4=rBase[r4]; byte[] bytes=new byte[2]; String str_12=str_r1+str_r2; int tempLow=Integer.parseInt(str_12, 16); bytes[0]=(byte) tempLow; String str_34=str_r3+str_r4; int tempHigh=Integer.parseInt(str_34, 16); bytes[1]=(byte)tempHigh; /** * 汉字显示 */ ctmp = new String(bytes,"gb2312"); break; default: itmp=random.nextInt(10)+48; ctmp=String.valueOf((char)itmp); break; } sRand+=ctmp; Color color=new Color(20+random.nextInt(110),20+random.nextInt(110),random.nextInt(110)); g.setColor(color); Graphics2D g2d_word=(Graphics2D)g; AffineTransform trans=new AffineTransform(); trans.rotate((45)*3.14/180,15*i+8,7); float scaleSize=random.nextFloat()+0.8f; if(scaleSize>1f) scaleSize=1f; trans.scale(scaleSize, scaleSize); g2d_word.setTransform(trans); g.drawString(ctmp, 15*i+18, 14); } HttpSession session=request.getSession(true); session.setAttribute("randCheckCode", sRand); g.dispose(); ImageIO.write(image,"JPEG",response.getOutputStream()); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
web.xml文件配置:
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <servlet> <servlet-name>PictureCheckCode</servlet-name> <servlet-class>com.servlet.PictureCheckCode</servlet-class> </servlet> <servlet-mapping> <servlet-name>PictureCheckCode</servlet-name> <url-pattern>/PictureCheckCode</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
3.测试验证码,编写JSP页面来验证是否可以输出验证图片,JSP代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>验证码</title> <script language="javascript"> function myReload() { document.getElementById("CreateCheckCode").src = document .getElementById("CreateCheckCode").src + "?nocache=" + new Date().getTime(); } </script> </head> <body> <form action="Check.jsp" method="post"> <input name="checkCode" type="text" id="checkCode" title="验证码区分大小写" size="8" ,maxlength="4" /> <img src="PictureCheckCode" id="CreateCheckCode" align="middle"> <a href="" onclick="myReload()"> 看不清,换一个</a> <input type="submit" value="提交" /> </form> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
Check.jsp,主要验证提交的数据是否和session中保存的验证码是否一致
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> <title>验证码校验</title> </head> <body> <% String checkcode=request.getParameter("checkCode"); if(checkcode.equals("")||checkcode==null){ out.print("<script>alert('请输入验证码');window.location.href('index.jsp')</script>"); }else{ if(!checkcode.equalsIgnoreCase((String)session.getAttribute("randCheckCode"))){ out.print("<script>alert('验证码不正确,请重新输入');history.back(-1);</script>"); }else{ out.print("登录成功"); } } %> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
一个简单的验证码登陆完成了。
参考文章参考文章