我对servlet+jsp当中使用token令牌避免用户重复提交表单的见解

首先我认为,要想从根本上避免用户重复提交表单,就一定要采用token令牌。使用js脚本在一定程度上能避免此类事情发生,但我认为这样做有缺陷。首先,利用js代码避免用户二次提交表单,在某些特殊情况下并不能起作用,详情请参见:http://www.cnblogs.com/xdp-gacl/p/3859416.html。个人认为最好的方法是综合采用token令牌和js脚本。

1、TokenUtil这个类主要用于生成token令牌(感谢_cuiyaoqiang的原创文章:http://blog.csdn.net/cuiyaoqiang/article/details/50960787):

package com.java.token;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import sun.misc.BASE64Encoder;

public class TokenUtil {
	/*
     *单例设计模式(保证类的对象在内存中只有一个)
     *1、把类的构造函数私有
     *2、自己创建一个类的对象
     *3、对外提供一个公共的方法,返回类的对象
     */
    private TokenUtil(){
    }

    private static final TokenUtil instance = new TokenUtil();

    /**
     * 返回类的对象
     * @return
     */
    public static TokenUtil getInstance(){
        return instance;
    }

    /**
     * 生成Token
     * Token:Nv6RRuGEVvmGjB+jimI/gw==
     * @return
     */
    public String makeToken(){

        String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
        //数据指纹   128位长   16个字节  md5
        try {
            MessageDigest md = MessageDigest.getInstance("md5");
            //对于给定数量的更新数据,digest 方法只能被调用一次。digest 方法被调用后,MessageDigest对象被重新设置成其初始状态。
            byte md5[] =  md.digest(token.getBytes());
            //base64编码--任意二进制编码明文字符   adfsdfsdfsf
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(md5);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

}
2、类TokenTools主要用于在session中设置token令牌,和验证令牌:

package com.java.token;

import javax.servlet.http.HttpSession;

public class TokenTools {
	
	public TokenTools(){}
	/* *功能:生成token令牌,并保存在session中
	 * *参数:tokenname是在session中token的名称
	 * *	session是要存储token的目标session
	 * *返回值:返回session字符串
	 * */
	public static String setToken(String tokenname, HttpSession session)
	{
		String token = TokenUtil.getInstance().makeToken();
		session.setAttribute(tokenname, token);
		return token;
	}
	/* *功能:验证token是否存在
	 * *参数:tokenname是在session中token的名称
	 * *	token是从表单中提取的令牌值
	 * *	session是存储token的目标session
	 * *返回值:如果令牌正确返回true,反之为false
	 * */
	public static boolean verifyToken(String tokenname, String token,  HttpSession session)
	{
		if(session.getAttribute(tokenname)==null)
		{
			return false;
		}
		
		String tokenInsession = session.getAttribute(tokenname).toString();
		//如果验证令牌通过,就重置session属性
		if(tokenInsession.equals(token))
		{
			session.removeAttribute(tokenname);
			return true;
		}
		return false;
	}

}
3、表单页面jsp,注意第17行,那里生成一个token:

<%@page import="com.java.token.TokenTools"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>

<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>





<%
session.setMaxInactiveInterval(30*60);
/*设置token令牌*/
String token = TokenTools.setToken("regist_token", session);
//System.out.println("jsp: "+token);
%>



用户注册


 

用户注册


用户 名:
密  码:
确认密码:
性  别男   
个人简介:
  
4、在servlet中验证token:

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub	
		req.setCharacterEncoding("UTF-8");
		
		String username,password,sex,note, token;
		token = req.getParameter("regist_token");
		
		//验证token1是否合法
		HttpSession session = req.getSession();
		//System.out.println("servlet: "+session.getAttribute("regist_token").toString());
		boolean pass = TokenTools.verifyToken("regist_token", token, session);
		
		if(pass==false)
		{
			System.out.println("token repeat submit!");
			req.setAttribute("msg", "请不要重复提交表单");
			req.getRequestDispatcher("/regist.jsp").forward(req, resp);
			return;
		}
		
		username = req.getParameter("username");
		password = req.getParameter("password");
		sex = req.getParameter("sex");
		note = req.getParameter("note");
		
		if(username==null||password==null
		||sex==null||note==null)
		{
			String path = req.getContextPath();
			String basePath = req.getScheme()+"://"+
			req.getServerName()+":"+
			req.getServerPort()+path+"/";
			resp.sendRedirect(basePath+"regist.jsp");
			return;
		}
		
		session.setAttribute("username", username);
		session.setAttribute("note", note);
		session.setAttribute("sex", sex);
		session.setAttribute("password", password);
		
		req.getRequestDispatcher("/usermain.jsp").forward(req, resp);
		return;
	}



你可能感兴趣的:(我对servlet+jsp当中使用token令牌避免用户重复提交表单的见解)