Servlet实现数字字母验证码图片(二):
生成验证码图片主要用到了一个BufferedImage类,如下:
使用登录的例子演示验证码的实现:
1、引入jquery-1.10.2.js文件,创建login.jsp,使用时间戳来刷新验证码
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>用户登录</title> 8 </head> 9 <script type="text/javascript" 10 src="js/jquery-1.10.2.js"></script> 11 12 <body> 13 <form method="post" 14 action="${pageContext.request.contextPath }/login.do"> 15 用户名:<input type="text" name="username" /><br /> 密 码:<input 16 type="text" name="password" /><br /> 17 <!-- img中的src属性中,配置VerifyImage的请求 --> 18 验证码:<br /> 19 <img id="imgObj" src="${pageContext.request.contextPath}/verifyCode.do" onclick="changeImg()"/> <input 20 type="text" name="verifyCode" /> <a href="javascript:void(0);" id="code" 21 onclick="changeImg()">看不清,换一张</a> <br /> <input type="checkbox" 22 value="1" name="rememberMe" />记住密码 <br /> <input type="submit" 23 value="登陆" /> 24 </form> 25 </body> 26 <script type="text/javascript"> 27 function changeImg() { 28 var imgSrc = $("#imgObj"); 29 var src = imgSrc.attr("src"); 30 //时间戳 ,为了使每次生成图片不一致,即不让浏览器读缓存,所以需要加上时间戳 31 var timestamp = (new Date()).valueOf(); 32 src =src +"?timestamp=" + timestamp;; 33 imgSrc.attr("src", src); 34 } 35 </script> 36 </html>
2、创建登录成功和登录失败后的页面index.jsp和error.jsp
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>用户首页</title> 8 </head> 9 <body> 10 登录成功! 11 </body> 12 </html>
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>登录失败</title> 8 </head> 9 <body> 10 登录失败... 11 </body> 12 </html>
3.创建画图servlet,VerifyImage.java
1 package com.utils; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.Graphics; 6 import java.awt.image.BufferedImage; 7 import java.io.IOException; 8 import java.io.OutputStream; 9 import java.util.Random; 10 11 import javax.imageio.ImageIO; 12 import javax.servlet.ServletException; 13 import javax.servlet.annotation.WebServlet; 14 import javax.servlet.http.HttpServlet; 15 import javax.servlet.http.HttpServletRequest; 16 import javax.servlet.http.HttpServletResponse; 17 18 @WebServlet("/verifyCode.do") 19 public class VerifyImage extends HttpServlet { 20 21 // 产生随即的字体 22 private Font getFont() { 23 Random random = new Random(); 24 Font font[] = new Font[5]; 25 font[0] = new Font("Ravie", Font.PLAIN, 24); 26 font[1] = new Font("Antique Olive Compact", Font.PLAIN, 24); 27 font[2] = new Font("Forte", Font.PLAIN, 24); 28 font[3] = new Font("Wide Latin", Font.PLAIN, 24); 29 font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, 24); 30 return font[random.nextInt(5)]; 31 } 32 33 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 34 throws ServletException, IOException { 35 // 设置响应头 Content-type类型 36 resp.setContentType("image/jpeg"); 37 // 以下三句是用于设置页面不缓存 38 resp.setHeader("Pragma", "No-cache"); 39 resp.setHeader("Cache-Control", "No-cache"); 40 resp.setDateHeader("Expires", 0); 41 42 OutputStream os = resp.getOutputStream(); 43 int width = 83, height = 30; 44 45 // 建立指定宽、高和BufferedImage对象 46 BufferedImage image = new BufferedImage(width, height, 47 BufferedImage.TYPE_INT_RGB); 48 49 Graphics g = image.getGraphics(); // 该画笔画在image上 50 Color c = g.getColor(); // 保存当前画笔的颜色,用完画笔后要回复现场 51 g.fillRect(0, 0, width, height); 52 53 char[] ch = "abcdefghigklmnopqrstuvwxyz" 54 .concat("ABCDEFGHIJKLMNOPQRSTUV").concat("WXYZ0123456789") 55 .toCharArray(); // 随即产生的字符串 56 // 不包括 i 57 // l(小写L) 58 // o(小写O) 59 // 1(数字1)0(数字0) 60 int length = ch.length; // 随即字符串的长度 61 String sRand = ""; // 保存随即产生的字符串 62 Random random = new Random(); 63 for (int i = 0; i < 4; i++) { 64 // 设置字体 65 g.setFont(getFont()); 66 // 随即生成0-9的数字 67 String rand = new Character(ch[random.nextInt(length)]).toString(); 68 sRand += rand; 69 // 设置随机颜色 70 g.setColor(new Color(random.nextInt(255), random.nextInt(255), 71 random.nextInt(255))); 72 g.drawString(rand, 20 * i + 6, 25); 73 } 74 // 产生随即干扰点 75 for (int i = 0; i < 40; i++) { 76 int x1 = random.nextInt(width); 77 int y1 = random.nextInt(height); 78 g.drawOval(x1, y1, 2, 2); 79 } 80 g.setColor(c); // 将画笔的颜色再设置回去 81 g.dispose(); 82 83 // 将验证码记录到session 84 req.getSession().setAttribute("safecode", sRand); 85 // 输出图像到页面 86 ImageIO.write(image, "JPEG", os); 87 } 88 89 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 90 throws ServletException, IOException { 91 doGet(req, resp); 92 } 93 94 }
4.创建登录验证处理servlet,LoginServlet.java
1 package com.utils; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.annotation.WebServlet; 7 import javax.servlet.http.Cookie; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 import org.apache.log4j.Logger; 13 14 @WebServlet("/login.do") 15 public class LoginServlet extends HttpServlet { 16 17 Logger log = Logger.getLogger(LoginServlet.class); 18 19 @Override 20 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 21 throws ServletException, IOException { 22 log.debug("开始执行doGet方法"); 23 this.doPost(req, resp); 24 } 25 26 @Override 27 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 28 throws ServletException, IOException { 29 log.debug("开始执行doPost方法"); 30 31 req.setCharacterEncoding("UTF-8"); 32 resp.setContentType("text/html;charset=UTF-8"); 33 34 log.debug("开始接收参数"); 35 String username = req.getParameter("username"); 36 String password = req.getParameter("password"); 37 String safeCode = req.getParameter("verifyCode"); 38 39 log.debug("接收到参数:username =" + username + ";password=" + password 40 + ";safecode=" + safeCode); 41 42 // 获取验证码 43 String sc = (String) req.getSession().getAttribute("safecode"); 44 log.warn("服务器中的验证码:" + sc); 45 // 忽略大小写处理: 46 if (!sc.equalsIgnoreCase(safeCode)) { 47 log.warn("验证码输入有误!"); 48 resp.sendRedirect("login.jsp"); 49 return; 50 } 51 52 String isRe = req.getParameter("rememberMe"); 53 log.debug("是否记住密码:" + isRe); 54 if ("1".equals(isRe)) { 55 /* 56 * 记住密码 在客户端的Cookie中,写入一个字符串标识 57 */ 58 // 创建cookie 59 log.debug("创建Cookie"); 60 Cookie cookie = new Cookie("rememberMe", username); 61 // 将cookie绑定到响应中 62 log.debug("绑定Cookie到响应中"); 63 resp.addCookie(cookie); 64 } 65 66 if ("admin".equals(username) && "admin".equals(password)) { 67 log.debug("登录成功,跳转到Index.jsp页面"); 68 req.getSession().setAttribute("loginuser", username); 69 resp.sendRedirect("index.jsp"); 70 } else { 71 log.debug("登录失败,跳转到error.jsp页面"); 72 resp.sendRedirect("error.jsp"); 73 } 74 75 } 76 77 }
5、结果
参考链接:https://blog.csdn.net/sinat_39955521/article/details/78922814
一次性验证码:
目的:一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码。
原理:
1,服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。
2,密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程。
参考链接:http://baijiahao.baidu.com/s?id=1552594243817616&wfr=spider&for=pc
项目下载:下载工程