一次性验证码

本文介绍了一次性图形验证码的实现方法,包括创建展示验证码图片的JSP页面、生成验证码的Servlet及验证过程。此外还提供了刷新验证码的方法以解决部分浏览器缓存问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自: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 >
RandomCodeServlet.java

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());
     }
 
}
LoginServlet.java

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());
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值