使用令牌实现防重复提交

重复提交的情景:

  一般控制重复提交主要是用在对数据库操作的控制上,比如插入、更新、删除等,由于更新、删除一般都是通过id来操作(例如: updateXXXById, removeXXXById),所以这类操作控制的意义不是很大(不排除个别现象),重复提交的控制也就主要是在插入时的控制了。

1.常见防重提交的方式主要有:js方式 验证码  令牌

2.这里主要介绍第三种:

其实从原理上来说,第二种跟第三种是一样的。都是通过生成随机数,存放于session,使得重复提交时获取到的数据与上一次发的数据不一致,从而不满足提交条件。

分三步:

1.初始化令牌值 AvoidSubmitFormAgain.initTokenProcessor(request, response); 生成token,并放置到session里

2.在页面上获取刚才生成的令牌值token

3.在后台对token进行校验:AvoidSubmitFormAgain.isTokenValid(request)  true:可以提交  false:重复提交

4.清除当前的令牌值:AvoidSubmitFormAgain.removeTokenProecessor(request);

下面是具体代码:

令牌生成器:TokenProcessor.java

package com.sie.commons;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import sun.misc.BASE64Encoder;

public class TokenProcessor {
	/*
	 * 1.把构造函数私有
	 * 2.自己创建一个
	 * 3.对外暴露一个方法,允许获取上面创建的对象
	 * */
	private static final TokenProcessor instance=new TokenProcessor();
	private TokenProcessor(){}
	public static TokenProcessor getInstance()
	{
		return instance;
	}
	public String generateToken()
	{
		String token=System.currentTimeMillis()+new Random().nextInt()+"";
		try {
			MessageDigest md=MessageDigest.getInstance("md5");
			byte[] md5=md.digest(token.getBytes());
			//base64编码
			BASE64Encoder encoder=new BASE64Encoder();
			
			return encoder.encode(md5);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
	}
	
}

第二个是我自己整合后一个令牌的操作工具AvoidSubmitFormAgain.java

package com.sie.commons;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 重复提交工具类
 * @author lyq
 *
 */
public class AvoidSubmitFormAgain {
	/**
	 * 初始化token
	 * @param request
	 * @param response
	 * @param path
	 * @throws ServletException
	 * @throws IOException
	 * @author lyq
	 * @date:2014-4-25 下午4:05:27
	 * @version :
	 */
	public static void initTokenProcessor(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//产生随机数
				TokenProcessor tp=TokenProcessor.getInstance();
				String token=tp.generateToken();
				
				request.getSession().setAttribute("token", token);
	}
	
	/**
	 * 清除token
	 * @param request
	 * @author lyq
	 * @date:2014-4-25 下午4:03:42
	 * @version :
	 */
	public static void removeTokenProecessor(HttpServletRequest request)
	{
		request.getSession().removeAttribute("token");
	}
	
	/**
	 * 对token的有效性进行判断
	 * @param request
	 * @return
	 * @author lyq
	 * @date:2014-4-25 下午4:07:03
	 * @version :
	 * 判断是否为重复提交
	 */
	@SuppressWarnings("unused")
	public static boolean isTokenValid(HttpServletRequest request) {
		String client_token=request.getParameter("token");
		if(client_token==null)
		{
			return false;
		}
		String server_token=(String)request.getSession().getAttribute("token");
		if(server_token==null)
		{
			return false;
		}
		if(!client_token.equals(server_token))
		{
			return false;
		}
		return true;
	}
}

  第三个是具体的使用逻辑,我们这里用于注册时的防重提交

public ActionForward user_registe(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws UserException {
		UserForm userform = (UserForm)form;
		//较验当前令牌与提交的是否相等,如果相同,则允许提交,否则,提交“重复提交”
if(!AvoidSubmitFormAgain.isTokenValid(request)) { userform.user_mess = "注册请求己提交,不要再重复提交,请重新注册"; return mapping.findForward("user_registe_resubmit_front"); } if(userservice.user_registe(userform.getUser())) { AvoidSubmitFormAgain.removeTokenProecessor(request); userform.user_mess = "用户注册成功,页面跳到登录页面"; request.setAttribute("userform",userform); return mapping.findForward("user_registe_success_front"); }
}

  

原文地址:https://www.cnblogs.com/liuyq/p/3689897.html