在登录页面和各种页面,会看到有验证码输入,这样做的目的是为了防止密码猜测工具破解密码,保护了用户密码安全,验证码只能使用一次,这样就给密码猜测工具带来了很大的困难,基本上阻断了密码猜测工具的使用。
可以使用session获得一次性验证码。其原理与利用Token机制解决重复重复提交问题一样。
先看一下登录页面,即显示验证码的页面,代码为:
<%@ 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>
</head>
<body>
<!-- src="<%=request.getContextPath() %>/check/captcha.jsp"> -->
<!-- src="<%=request.getContextPath() %>/validateColorServlet"> -->
<form action="<%=request.getContextPath() %>/checkCodeServlet" method="post">
姓名:<input type="text" name="name" /> <br>
验证码:<input type="text" name="CHECK_CODE_PARAM_NAME" />
<img alt="" src="<%=request.getContextPath() %>/validateColorServlet"><br>
<input type="submit" value="Submit"> <br>
</form>
</body>
</html>
验证码存放在一张图片上,那图片是通过servlet产生的,在servlet中先产生验证码存放到session中,供以后验证使用,然后在画一张图片,将验证码无规则的放在图片上,在图片上画上干扰字符,然后就可以啦。产生验证码的代码如下:
package com.ali.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ValidateColorServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 设置验证图片的宽度, 高度, 验证码的个数
private int width = 152;
private int height = 40;
private int codeCount = 4;
private static final String CHECK_CODE_KEY ="CHECK_CODE";
// 验证码字体的高度
private int fontHeight = 4;
// 验证码中的单个字符基线. 即:验证码中的单个字符位于验证码图形左上角的 (codeX, codeY) 位置处
private int codeX = 0;
private int codeY = 0;
// 验证码由哪些字符组成
char[] codeSequence = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz23456789"
.toCharArray();
// 初始化验证码图形属性
public void init() {
fontHeight = height - 2;
codeX = width / (codeCount + 2);
codeY = height - 4;
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 定义一个类型为 BufferedImage.TYPE_INT_BGR 类型的图像缓存
BufferedImage buffImg = null;
buffImg = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
// 在 buffImg 中创建一个 Graphics2D 图像
Graphics2D graphics = null;
graphics = buffImg.createGraphics();
// 设置一个颜色, 使 Graphics2D 对象的后续图形使用这个颜色
graphics.setColor(Color.WHITE);
// 填充一个指定的矩形: x - 要填充矩形的 x 坐标; y - 要填充矩形的 y 坐标; width - 要填充矩形的宽度; height
// - 要填充矩形的高度
graphics.fillRect(0, 0, width, height);
// 创建一个 Font 对象: name - 字体名称; style - Font 的样式常量; size - Font 的点大小
Font font = null;
font = new Font("", Font.BOLD, fontHeight);
// 使 Graphics2D 对象的后续图形使用此字体
graphics.setFont(font);
graphics.setColor(Color.BLACK);
// 绘制指定矩形的边框, 绘制出的矩形将比构件宽一个也高一个像素
graphics.drawRect(0, 0, width - 1, height - 1);
// 随机产生 20 条干扰线, 使图像中的认证码不易被其它程序探测到
Random random = null;
random = new Random();
// graphics.setColor(Color.GREEN);
// for (int i = 0; i < 20; i++) {
// int x = random.nextInt(width);
// int y = random.nextInt(height);
// int x1 = random.nextInt(20);
// int y1 = random.nextInt(20);
// graphics.drawLine(x, y, x + x1, y + y1);
// }
// 产生干扰点
for (int i = 0; i < 256; i++) {
graphics.setColor(new Color(random.nextInt(255), random
.nextInt(255), random.nextInt(255)));
int x = random.nextInt(width);
int y = random.nextInt(height);
graphics.drawOval(x, y, 1, 1);
}
// 创建 randomCode 对象, 用于保存随机产生的验证码, 以便用户登录后进行验证
StringBuffer randomCode;
randomCode = new StringBuffer();
for (int i = 0; i < codeCount; i++) {
// 得到随机产生的验证码数字
String strRand = null;
strRand = String.valueOf(codeSequence[random.nextInt(36)]);
randomCode.append(strRand);
// 用随机产生的颜色将验证码绘制到图像中
// graphics.setColor(Color.gray);
graphics.setColor(new Color(random.nextInt(255), random
.nextInt(255), random.nextInt(255)));
graphics.drawString(strRand, (i + 1) * codeX, codeY);
}
//将随机串放入session
request.getSession().setAttribute(CHECK_CODE_KEY, randomCode.toString());
// 禁止图像缓存
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 将图像输出到输出流中
ServletOutputStream sos = null;
sos = response.getOutputStream();
ImageIO.write(buffImg, "jpeg", sos);
sos.close();
}
}
在checkCodeServlet中通过比较session中存放的验证码和用户输入的验证码,如果匹配则进行下一步判断,如果不匹配直接输出验证码不匹配的问题。代码为:
package com.ali.shoppingcart.servlet;
import java.io.IOException;
import java.io.PrintWriter;
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 CheckCodeServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(false);
if (session == null) {
out.print("验证码处理问题");
return;
}
String saveCode = (String) session.getAttribute("CHECK_CODE");
if (saveCode == null) {
out.print("验证码处理问题");
return;
}
String checkCode = request.getParameter("CHECK_CODE_PARAM_NAME");
if (!saveCode.equals(checkCode)) {
out.print("验证码无效!");
return;
}
session.removeAttribute("CHECK_CODE");
out.print("验证码通过,服务器正在校验用户名和密码!");
}
}
参考:http://blog.csdn.net/youyajie/article/details/8004959