转自:http://my.oschina.net/hongdengyan/blog/181998
一次性验证码的作用
防止暴力破解。
二、实现
1.创建jsp页面,在页面中添加一个img标签,指向一个生成图片的servlet,设置img宽度和高度
2.创建生成图形验证码的Servlet
该Servlet根据生成的随机码产生一个图形流并返回,可以将该图形做一些混淆操作,同时将该随机码保存到当前用户session中。
3.验证码比对
将用户提交上来的验证码和保存到当前用户session中的随机码进行比对。
4.刷新验证码。
使用javascript刷新验证码。
三、示例代码
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!
DOCTYPE
html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<
html
>
<
head
>
<
meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<
title
>Insert title here</
title
>
<
script
type
=
"text/javascript"
>
function change() {
var contextPath = document.getElementById("contextPath").value;
document.getElementById("randomCode").src = contextPath+"/randomCode?"+Math.random();
}
</
script
>
</
head
>
<
body
>
<
input
type
=
"hidden"
id
=
"contextPath"
value="<%=request.getContextPath() %>">
<
form
method
=
"post"
action="<%=request.getContextPath() %>/login">
<
table
>
<
tr
>
<
td
>姓名:</
td
>
<
td
><
input
type
=
"text"
name
=
"username"
/></
td
>
</
tr
>
<
tr
>
<
td
>密码:</
td
>
<
td
><
input
type
=
"password"
name
=
"password"
/></
td
>
</
tr
>
<
tr
>
<
td
>验证码:</
td
>
<
td
><
input
type
=
"text"
name
=
"randomCode"
/></
td
>
</
tr
>
<
tr
>
<
td
></
td
>
<
td
colspan
=
"2"
><
img
alt
=
""
src="<%=request.getContextPath() %>/randomCode" width="100"
height="35" id="randomCode" title="看不清楚,点击换一张" onclick="change()" /></
td
>
</
tr
>
<
tr
>
<
td
colspan
=
"2"
><
input
type
=
"submit"
value
=
"登陆"
/></
td
>
</
tr
>
</
table
>
</
form
>
</
body
>
</
html
>
package
cn.heimar.randomCode;
import
java.awt.Color;
import
java.awt.Font;
import
java.awt.Graphics;
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;
public
class
RandomCodeServlet
extends
HttpServlet {
@Override
protected
void
service(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException {
int
randomNumber =
5
;
// 图片宽度
int
width =
100
;
// 图片高度
int
height =
35
;
// 创建随机码
char
[] ranlist =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
.toCharArray();
StringBuilder sb =
new
StringBuilder();
Random randomer =
new
Random();
for
(
int
i =
0
; i < randomNumber; i++) {
sb.append(ranlist[randomer.nextInt(ranlist.length)]);
}
// 保存到session中
HttpSession session = req.getSession();
session.setAttribute(
"RANDOM_IN_SESSION"
, sb.toString());
// 画画
// 创建一个图片对象
BufferedImage image =
new
BufferedImage(width, height,
BufferedImage.TYPE_INT_BGR);
// 得到图片对象对应的绘画缓存,绘画都在Graphics对象上
Graphics g = image.getGraphics();
// 绘制背景
g.setColor(Color.WHITE);
// 填充矩形
g.fillRect(
0
,
0
, width, height);
// 绘制边框
g.setColor(Color.BLACK);
g.drawRect(
0
,
0
, width -
1
, height -
1
);
// 绘制文字
g.setColor(Color.GRAY);
g.setFont(
new
Font(
"宋体"
, Font.ITALIC,
24
));
g.drawString(sb.toString(),
13
, height -
9
);
//绘制干扰点
for
(
int
i =
0
; i <
300
; i++) {
g.fillRect(randomer.nextInt(width -
1
),
randomer.nextInt(height -
1
),
1
,
1
);
}
// 关闭绘画资源
g.dispose();
//清除图片缓存:IE7 firefox验证码没有反应问题
//设定网页的到期时间,一旦过期则必须到服务器上重新调用
resp.setDateHeader(
"Expires"
,-
1
);
//Cache-Control指定请求和响应遵循的缓存机制 no-cache指示请求或响应消息不能缓存
resp.setHeader(
"Cache-Control"
,
"no-cache"
);
//是用于设定禁止浏览器从本地机的缓存中调阅页面内容,设定后一旦离开网页就无法从Cache中再调出
resp.setHeader(
"Pragma"
,
"no-cache"
);
// 输出
ImageIO.write(image,
"JPG"
, resp.getOutputStream());
}
}
package
cn.heimar.randomCode;
import
java.io.IOException;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
javax.servlet.http.HttpSession;
public
class
LoginServlet
extends
HttpServlet {
@Override
protected
void
service(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException {
HttpSession session = req.getSession();
String randomForm = req.getParameter(
"randomCode"
);
String username = req.getParameter(
"username"
);
String randomInSession = (String) session
.getAttribute(
"RANDOM_IN_SESSION"
);
if
(randomForm.equals(randomInSession)) {
req.getRequestDispatcher(
"/WEB-INF/success.jsp"
).forward(req, resp);
session.removeAttribute(
"RANDOM_IN_SESSION"
);
}
else
{
resp.sendRedirect(req.getContextPath()+
"/login.jsp"
);
}
}
}
四、个别浏览器验证码不能刷新的问题
1.问题说明
在IE6下面图片刷新正常,但IE7和Firefox浏览器刷新不成功。2.原因分析
如果新的图片跟旧的图片地址不一样,图片刷新会正常。但是验证码功能访问图片的地址是一样的。因此浏览器自动读取的是缓存中的内容。3.解决方法
3.1利用随机数
将js中路径后加上Math.random();
1
2
3
4
|
function
change() {
var
contextPath = document.getElementById(
"contextPath"
).value;
document.getElementById(
"randomCode"
).src = contextPath+
"/randomCode?"
+Math.random();
}
|
3.2利用时间戳
1
2
3
4
|
function
change() {
var
contextPath = document.getElementById(
"contextPath"
).value;
<span></span>document.getElementById(
"randomCode"
).src = contextPath+
"/randomCode?"
+Date.parse(
new
Date());
}
|