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

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

1、TokenUtil这个类主要用于生成token令牌(感谢_cuiyaoqiang的原创文章:http://blog.youkuaiyun.com/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"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<script src="https://code.jquery.com/jquery-2.2.4.js" 
integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" 
crossorigin="anonymous"></script>
<%
session.setMaxInactiveInterval(30*60);
/*设置token令牌*/
String token = TokenTools.setToken("regist_token", session);
//System.out.println("jsp: "+token);
%>

<script>
        $(document).ready(function () {

            function checkPassword() {
                var pwdStr = $("#password").val();
                //alert(pwdStr);
                var repwdStr = $("#repassword").val();

                if (pwdStr == "" || repwdStr == "") {
                    $("#pwdNotice").text("密码仅由数字、字母组成(区分大小写)。");
                    $("#pwdNotice").css("color", "green");
                    return false;
                }

                //如果两次输入的密码不一致
                if (pwdStr != repwdStr) {
                    $("#pwdNotice").text("两次输入的密码不一致!");
                    $("#pwdNotice").css("color", "red");
                    return false;
                }
                else {
                    $("#pwdNotice").text("密码设置符合要求。");
                    $("#pwdNotice").css("color", "green");
                    return true;
                }
            };

            setInterval(checkPassword, 500);
            //当且仅当核对密码合法时提交表单
            $("#registForm").submit(function () {
                return checkPassword();
            });
           

        });
    </script>

<title>用户注册</title>
</head>
<body>
 <h3>用户注册</h3><hr>
    <form id="registForm" action="Regist" method="post">
        用户 名:<input type="text" name="username" value=""><br>
        密  码:<input type="password" id="password" name="password" value="qw"><br>
        确认密码:<input type="password" id="repassword" name="password2" value=""><span id="pwdNotice"></span><br>
        性  别<input type="radio" name="sex" value="男" checked="checked">男
          <input type="radio" name="sex" value="女">女<br>
        个人简介:<input type="text" name="note"><br>
        <input type="hidden" name="regist_token" value="<%=token%>">
        <input type="submit" value="注册">  
    </form>

</body>
</html>
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;
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值