`

Java-web放重复提交、动态验证码

阅读更多
一、项目中可能产生重复提交的情况:
    1,由于服务器缓慢或网络延迟的原因,重复点击提交按钮.
    2,已经提交成功,刷新成功页面(forward).
    3,已经提交成功,通过回退,再次点击提交按钮.
    注意:
1,回退后,刷新表单页面,再次提交这时不是重复提交,而是发送新的请求
2,在Firefox下,重复提交到同一地址无效
二、解决表单重复提交方案:

  1、方案一,利用javaScript:
    解决了反复点击按钮的重复提交请求,但是没有解决刷新页面重复提交.
	var flag=false;
	function save(){
	     if(!flag){
	     	document.forms[0].submit();
	     	flag=true;
	     }else{
	     	alert("您已经提交了页面");
	     }
	 }

    注意:
         如果使用的<input type="submit">,则需要将form表单的onsubmit="return false;",或者将submit按钮的onClick="return save()",并让save方法始终返回flase;

  2、利用唯一的随机字符串(使用session)
   (1)UUID:
        包含有FORM表单的页面必须通过一个服务器程序动态产生,服务器程序为每次产生的页面中的FORM表单都分配一个唯一的随机标识号,并在FORM表单的一个隐藏字段中设置这个标识号,同时在当前用户的Session域中保存这个标识号。
        当用户提交FORM表单时,负责接收这一请求的服务器程序比较FORM表单隐藏字段中的标识号与存储在当前用户的Session域中的标识号是否相同,如果相同则处理表单数据,处理完后清除当前用户的Session域中存储的标识号。在下列情况下,服务器程序将忽略提交的表单请求:
    当前用户的Session中不存在表单标识号
    用户提交的表单数据中没有标识号字段
    存储在当前用户的Session域中的表单标识号与表单数据中的标识号不同
    浏览器只有重新向WEB服务器请求包含FORM表单的页面时,服务器程序才又产生另外一个随机标识号,并将这个标识号保存在Session域中和作为新返回的FORM表单中的隐藏字段值。

使用UUID防止重复提交的步骤 :
a、使用UUID类可以生成随机字符串
b、getUUIDString,生成UUID值并存放到session中
c、验证,通过表单中传来的uuid值与session中的值进行对比.
4、重置uuid值.

示例代码:
package cn.itcast.cd.util;

import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;

public class TokenUtil {

	public static void getToken(HttpServletRequest request) {
		String randomValue = UUID.randomUUID().toString(); // 往session中值
		String randomName = UUID.randomUUID().toString();// 往session中名字

		request.setAttribute("randomValue", randomValue);
		request.setAttribute("randomName", randomName);
		request.getSession().setAttribute(randomName, randomValue);
	}

	/**
	 * 请求表单中的随机数和session中的随机数对应上 return true
	 * 
	 * @param request
	 * @return
	 */
	public static Boolean validate(HttpServletRequest request) {
		// 得到页面上传递过来的..
		String randomValue = request.getParameter("randomValue");
		String randomName = request.getParameter("randomName");

		// 得到session中的
		String randomValueInSesson = (String) request.getSession()
				.getAttribute(randomName);
		return StringUtils.isNotBlank(randomValueInSesson)
				&& StringUtils.isNotBlank(randomValue)
				&& randomValue.equals(randomValueInSesson);
	}

	public static void resetToken(HttpServletRequest request) {
		String randomName = request.getParameter("randomName");
		request.getSession().removeAttribute(randomName);
	}
}

   (2)strut1的同步令牌
   (3)利用Session实现一次性验证码
     一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码,其原理与利用Session防止表单重复提交的原理基本一样,只是将表单标识号变成了验证码的形式,并且要求用户将提示的验证码手工填写进一个表单字段中,而不是通过表单的隐藏字段自动回传给服务器。
    服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。
    密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程。
   
    Servlet输出图形验证码:
      BufferedImage用于生成内存图形
      BufferedImage image=new       BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
      Graphics用于生成可绘制的图形对象
      Graphics g=image.getGraphics();
      g.fillRect(0, 0, width, height);//填充矩形
      g.drawRect(0, 0, width-1, height-1);//绘制矩形
      g.setFont(new Font("宋体",Font.BOLD,35));//设置字体
      g.drawString(rank, codeX*(i+1), codeY);//输出字符串
      g.drawOval(x, y, 0, 0);//绘制混淆线
      g.dispose();
      ImageIO对象,用于输出图片
      ImageIO.write(image, "jpg", response.getOutputStream());//输出图片

附:IE7  firefox验证码没有反应问题   
    出现的问题:在IE6下面图片修改正常,但在IE7和Firefox下面却不刷新
    情况分析:如果新的图片跟旧的图片地址不一样,效果是会出来的。即:图片有发生改变。 但像”验证码“这种功能,由于是servlet动态生成的图片,新旧图片的地址是一样的。鉴于上述情况,有可能是因为图片地址是一样的,而导致浏览器自动读缓存。

    解决方法一(利用随机数)
      把javascript改成这样即可:   function nextpic(){
            var img_=document.getElementById("pic");    
            img_.src="${pageContext.request.contextPath}/
                   imageServlet?"+Math.random();
       }
       即:每次的访问地址都不一样,因为有加随机数。所以问题解决 。
    解决方法二(利用时间戳)
      把javascript改成这样即可:
      function nextPic(){
           alert(Date.parse(new Date()));
           var pic=document.getElementById("pic");
           pic.src="${pageContext.request.contextPath}/
imageServlet?"+Date.parse(new Date());
      }

      Date.parse(): 解析一个包含日期的字符串,并返回该日期与 1970 年 1 月 1 日午夜之间所间隔的毫秒数

示例代码:
package cn.itcast.cd.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

public class LoginServlet extends HttpServlet {
	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void service(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		String code = request.getParameter("code");
		String randomCode = (String) request.getSession().getAttribute(
				"randomCode");
		if (StringUtils.equalsIgnoreCase(code, randomCode)) {
			System.out.println("执行正常的业务逻辑");
		} else {
			request.setAttribute("error", "验证码出错");
			request.getRequestDispatcher("/login.jsp").forward(request,
					response);
		}
	}

}

package cn.itcast.cd.servlet;

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 java.util.UUID;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class RandomCodeServlet
 */
public class RandomCodeServlet extends HttpServlet {
	protected void service(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		String randomCode = (UUID.randomUUID().toString()).substring(0, 4);
		request.getSession().setAttribute("randomCode", randomCode);

		response.setContentType("image/jpeg"); // 因为向客户端发送的内容是图片. 所以用这种内容类型

		int width = 100;
		int height = 50;
		// >>1.创建一个图片对象
		BufferedImage image = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_BGR);

		// >>2.得到画布
		Graphics graphics = image.getGraphics();

		// >>3.开始在图片上画画

		// >>3.1 用白色填充. 首先要设置上下文的颜色
		graphics.setColor(Color.white);// 设置白色
		graphics.fillRect(1, 1, width - 2, height - 2);

		// >>3.2 用黑色写文字
		graphics.setColor(Color.black);
		graphics.setFont(new Font("宋体", Font.BOLD, 30));
		graphics.drawString(randomCode, width / 6, height / 2 + 5);

		// >>3.3 画混淆内容
		graphics.setColor(Color.red);
		for (int i = 0; i < 50; i++) {
			graphics.fillOval(new Random().nextInt(width),
					new Random().nextInt(height), 3, 3);
		}
		for (int i = 0; i < 10; i++) {
			graphics.setColor(new Color[] { Color.red, Color.blue, Color.GRAY }[new Random()
					.nextInt(3)]);
			graphics.drawLine(new Random().nextInt(width),
					new Random().nextInt(height), new Random().nextInt(width),
					new Random().nextInt(height));
		}

		// >>4.关闭画布,释放资源...
		graphics.dispose();
		// 输出图片

		ImageIO.write(image, "JPG", response.getOutputStream());
	}

}


<%@ 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 changeImage() {
		document.getElementById("randomCode").src = "/randomCode?"
				+ Math.random();解决点击验证码没有反应问题
	}
</script>
</head>
<body>
	<form action="/login" method="post">
		用户名:<input name="username" type="text"><br /> 密码:<input
			name="password" type="password"><br /> 验证码:<input name="code"
			type="text"><img alt="" src="/randomCode" id="randomCode"
			style="cursor: pointer;" onclick="changeImage()"> ${error}<br />
		<input type="submit" value="登录">
	</form>
</body>
</html>
分享到:
评论

相关推荐

    成功的验证码案例-----struts验证码demo

    5. **图片生成**:验证码的图像通常是动态生成的,这通常涉及到一些图形库,如Java的`java.awt.image.BufferedImage`和`java.awt.Color`等,用于创建随机颜色和形状的文本。 6. **安全考虑**:为了提高安全性,...

    Java实现验证码验证功能

    在Web应用中,验证码通常表现为一串随机字符或者图像,用户需要正确输入才能完成某个操作,如注册、登录或提交表单。 在Java中,实现验证码验证通常分为以下几个步骤: 1. **生成验证码**: - 首先,我们需要创建...

    防止页面刷新重复提交的方法.

    防止页面刷新重复提交是 Web 开发中非常重要的问题,为了防止这种问题,我们可以使用验证码方法、Token 方法、AJAX 方法等。验证码方法是最简单、最effective 的方法,Token 方法可以防止 CSRF 攻击,AJAX 方法可以...

    Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目

    Java图形验证码技术是一种用于验证用户身份的安全机制,广泛应用于Web应用程序和桌面软件(Java Web、JavaSE项目)中,防止自动化的机器人或者恶意脚本进行非法操作,如批量注册、频繁登录尝试等。EasyCaptcha项目是...

    JAVA实现注册页面验证码刷新

    - **重定向(Redirect)**:在某些情况下,如果需要避免表单重复提交,服务器可能会选择重定向用户到另一个页面。 6. **安全考虑**: - **验证码过期**:为了防止会话固定攻击,验证码应设置一个较短的有效期,如...

    Servlet生成动态验证码

    在Web应用程序中,验证码是一种常用的防止机器人或恶意用户自动操作的安全机制。Servlet生成动态验证码涉及到的主要知识点包括Servlet生命周期、HTTP请求响应流程、图像处理以及随机数生成。 1. Servlet生命周期: ...

    java工具类——验证码(VerifyCode)

    - 为了防止重复刷新导致验证码改变,可以使用`session`对象存储当前的验证码内容,同时在客户端通过JavaScript获取图片的`src`,并在表单提交时一并发送验证码值。 4. **验证过程** - 客户端输入验证码后,将其值...

    动态验证码

    动态验证码在IT行业中是网络安全的重要组成部分,主要用于防止自动化的机器人或恶意软件进行非法操作,...通过理解和掌握这些知识点,开发者可以创建出安全、有效的Java动态验证码系统,为Web应用提供更好的安全防护。

    不能重复提交

    - **使用验证码**:通过显示验证码图片,用户需要输入正确的验证码才能提交表单,这种方式可以有效防止自动化工具的重复提交行为。 - **设置超时时间**:通过限制表单提交的时间间隔来避免短时间内多次提交的情况...

    Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目.zip

    Java图形验证码技术是一种防止自动化程序(如机器人或恶意脚本)进行非法操作的安全机制,它通常用于Web应用程序的用户登录、注册等环节,确保提交的数据是由真实人类而非计算机程序提供的。EasyCaptcha是一个强大的...

    SSM实现登录验证码功能

    SSM(Spring、SpringMVC、MyBatis)是一个经典的Java web开发框架组合,它将Spring的核心容器、Spring MVC作为视图控制器以及MyBatis作为持久层框架集成在一起,为开发者提供了一种高效且灵活的开发方式。...

    java 实现验证码(servlet+jsp)

    在Java Web开发中,我们可以使用Servlet和JSP来实现一个简单的图形验证码。以下将详细介绍如何利用这两个技术进行验证码的实现。 首先,理解验证码的基本原理:验证码是一种通过图像显示随机字符或数字的方式,用户...

    Java实现五分钟内重复获取返回同一个短信验证码

    在用户提交验证码时,再次调用`fetchOrGenerateCode`,如果返回的验证码与用户提交的一致且未过期,则验证成功。 这就是使用Java实现五分钟内重复获取返回相同短信验证码的基本思路。在实际开发中,还需要考虑错误...

    jsp java 生成中文验证码

    - **安全性校验**:在用户提交验证码后,检查他们输入的值是否与服务器存储的值匹配,如果不匹配则拒绝请求。 - **可访问性**:对于视觉障碍的用户,可以提供音频验证码作为替代。 - **性能优化**:批量生成验证码并...

    java验证码

    在Java Web开发中,我们可以使用多种方式来实现验证码功能。这里,我们主要讨论与"java验证码"相关的知识点,包括`CodeCheckServlet`、`web.xml`配置以及HTML文件的应用。 1. **验证码技术原理**: - 图像验证码:...

    验证码生成类大全

    在Web应用中,验证码通常需要用户在提交表单前输入图像上显示的一串随机字符,以此验证用户是真人而非计算机程序。以下是一些关于验证码生成类的关键知识点: 1. **验证码类型**: - 图像验证码:最常见的一种形式...

    jsp文件动态验证码

    JSP(JavaServer Pages)是Java平台上的一种服务器端脚本语言,可以用来创建动态Web页面。在JSP中实现动态验证码,能确保用户交互过程的安全性。 **1. 验证码的基本原理** 验证码的主要目的是区分人类用户与计算机...

    Java验证码

    在这个Java验证码项目中,我们看到包括了Java类、JSP(Java Server Pages)源码以及web.xml配置文件,这些都是构建Java Web应用的关键组件。 首先,Java类通常包含了验证码的生成逻辑。验证码生成器可能包括以下几...

    Java以ajax方式获取后台生成验证码后台验证

    在IT行业中,尤其是在Web开发领域,验证码是一种常用的安全机制,用于防止自动化的恶意攻击,比如机器人注册、垃圾邮件发送等。本话题将深入探讨如何在Java后端与前端使用Ajax技术来实现验证码的获取和验证,以提升...

    java发送注册短信验证码demo

    在用户提交注册信息后,servlet会接收到这些请求,并进行业务逻辑处理,比如生成随机的短信验证码、调用短信服务API发送验证码以及验证用户输入的验证码是否与发送的一致。 短信验证码的发送通常涉及到第三方的短信...

Global site tag (gtag.js) - Google Analytics