利用struts的同步令牌机制避免form的重复提交

转载 2015年07月07日 11:28:35
 

利用struts的同步令牌机制避免form的重复提交

分类: 学习笔记 1182人阅读 评论(0) 收藏 举报
 
基本原理:  
  服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。 
    根据用户会话ID和当前系统时间来生成一个唯一(对于每个会话)令牌的,具体实现可以参考SynchroToken类中的generateToken()方法。 

1、在待提交的jsp页面中生成令牌并保存在session和request(在form表单里增加一个hiddean元素); 
    //设置同步令牌值,同时存放在session和request中 
    SynchroToken synchroToken = SynchroToken.getInstance(); 
    String token_Key = synchroToken.generateToken(request); 
    session.setAttribute(ItsConstants.TRANSACTION_TOKEN_KEY,token_Key); 

    <input type="hidden" name="<%=ItsConstants.REQUEST_TOKEN_KEY %>" value="<%=token_Key %>"> 

在存放常量的类ItsConstants事先定义2个常量: 
    /** 处理重复表单提交存放在session中的key name */ 
    public static final String TRANSACTION_TOKEN_KEY = "SS_TOKEN_NAME"; 
    /** 处理重复表单提交存放在REQUEST中的key name */ 
    public static final String REQUEST_TOKEN_KEY = "RQ_TOKEN_NAME"; 

2、在servlet端进行验证; 
boolean ifDoubleSubmit = SynchroToken.getInstance().isTokenValid(HttpServletRequest, true); 
方法isTokenValid()会比较自动获取session.getAttribute(ItsConstants.TRANSACTION_TOKEN_KEY)和req.getParameter(ItsConstants.REQUEST_TOKEN_KEY)的值并进行比较,该方法的第二个参数“true”表示比较完之后从session中删除该令牌session.removeAttribute(ItsConstants.TRANSACTION_TOKEN_KEY); 

3、类SynchroToken的代码如下: 
package common; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpSession; 

/** 
* 利用同步令牌(Token)机制来解决Web应用中重复提交的问题 

* @author Tony Lin 
* @since 2008-9-9 
* @version 1.0 
* @see Struts中的TokenProcessor类 
*/ 
public class SynchroToken { 
    /** 
     * The singleton instance of this class. 
     */ 
    private static SynchroToken instance = new SynchroToken(); 
    /** 
     * Retrieves the singleton instance of this class. 
     */ 
    public static SynchroToken getInstance() { 
        return instance; 
    } 
    /** 
     * Protected constructor for TokenProcessor.  Use TokenProcessor.getInstance() 
     * to obtain a reference to the processor. 
     */ 
    protected SynchroToken() { 
        super(); 
    } 
    /** 
     * Return <code>true</code> if there is a transaction token stored in 
     * the user's current session, and the value submitted as a request 
     * parameter with this action matches it.  Returns <code>false</code> 
     * under any of the following circumstances: 
     * <ul> 
     * <li>No session associated with this request</li> 
     * <li>No transaction token saved in the session</li> 
     * <li>No transaction token included as a request parameter</li> 
     * <li>The included transaction token value does not match the 
     *     transaction token in the user's session</li> 
     * </ul> 
     * 
     * @param request The servlet request we are processing 
     */ 
    public synchronized boolean isTokenValid(HttpServletRequest request) { 
        return this.isTokenValid(request, false); 
    } 
    /** 
     * Return <code>true</code> if there is a transaction token stored in 
     * the user's current session, and the value submitted as a request 
     * parameter with this action matches it.  Returns <code>false</code> 
     * <ul> 
     * <li>No session associated with this request</li> 
     * <li>No transaction token saved in the session</li> 
     * <li>No transaction token included as a request parameter</li> 
     * <li>The included transaction token value does not match the 
     *     transaction token in the user's session</li> 
     * </ul> 
     * 
     * @param request The servlet request we are processing 
     * @param reset Should we reset the token after checking it? 
     */ 
    public synchronized boolean isTokenValid( 
        HttpServletRequest request, 
        boolean reset) { 
        // Retrieve the current session for this request 
        HttpSession session = request.getSession(false); 
        if (session == null) { 
            return false; 
        } 
        // Retrieve the transaction token from this session, and 
        // reset it if requested 
        String saved = (String) session.getAttribute(ItsConstants.TRANSACTION_TOKEN_KEY);         
        if (saved == null) { 
            return false; 
        } 
        if (reset) { 
            this.resetToken(request); 
        } 
        // Retrieve the transaction token included in this request 
        String token = request.getParameter(ItsConstants.REQUEST_TOKEN_KEY); 
        if (token == null) { 
            return false; 
        } 
        return saved.equals(token); 
    } 
    /** 
     * Reset the saved transaction token in the user's session.  This 
     * indicates that transactional token checking will not be needed 
     * on the next request that is submitted. 
     * 
     * @param request The servlet request we are processing 
     */ 
    public synchronized void resetToken(HttpServletRequest request) { 
        HttpSession session = request.getSession(false); 
        if (session == null) { 
            return; 
        } 
        session.removeAttribute(ItsConstants.TRANSACTION_TOKEN_KEY); 
    } 
    /** 
     * Save a new transaction token in the user's current session, creating 
     * a new session if necessary. 
     * 
     * @param request The servlet request we are processing 
     */ 
    public synchronized void saveToken(HttpServletRequest request) { 
        HttpSession session = request.getSession(); 
        String token = generateToken(request); 
        if (token != null) { 
            session.setAttribute(ItsConstants.TRANSACTION_TOKEN_KEY, token); 
        } 
    } 
    /** 
     * Generate a new transaction token, to be used for enforcing a single 
     * request for a particular transaction. 
     * 
     * @param request The request we are processing 
     */ 
    public String generateToken(HttpServletRequest request) { 
        HttpSession session = request.getSession(); 
        try { 
            byte id[] = session.getId().getBytes(); 
            byte now[] = new Long(System.currentTimeMillis()).toString().getBytes(); 
            MessageDigest md = MessageDigest.getInstance("MD5"); 
            md.update(id); 
            md.update(now); 
            return this.toHex(md.digest()); 
        } catch (IllegalStateException e) { 
            return null; 
        } catch (NoSuchAlgorithmException e) { 
            return null; 
        } 
    } 
    /** 
     * Convert a byte array to a String of hexadecimal digits and return it. 
     *<p> 
     *<strong>WARNING</strong>: This method is not part of TokenProcessor's 
     *public API.  It's provided for backward compatibility only. 
     *</p> 
     * @param buffer The byte array to be converted 
     */ 
    public String toHex(byte buffer[]) { 
        StringBuffer sb = new StringBuffer(); 
        String s = null; 
        for (int i = 0; i < buffer.length; i++) { 
            s = Integer.toHexString((int) buffer[i] & 0xff); 
            if (s.length() < 2) { 
                sb.append('0'); 
            } 
            sb.append(s); 
        } 
        return sb.toString(); 
    } 

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

Session Token机制-Struts2中防止表单重复提交的两种方式(一)

当用户填写完表单后,在提交过一次后,若用户做如下操作比如再次点击提交、刷新页面、提交页面呈现后点击后退按钮,都会导致表单重复提交。如果信息需要存储到后台数据库中,重复提交就会再次向数据库中插入用户信息...
  • snow_7
  • snow_7
  • 2016年05月24日 20:32
  • 2041

Java 使用Token令牌防止表单重复提交

Java 使用Token令牌防止表单重复提交的步骤: - 在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。 - 将...
  • cuiyaoqiang
  • cuiyaoqiang
  • 2016年03月23日 10:11
  • 7308

JavaWeb 如何防止表单重复提交 - 使用Token,令牌

JavaWeb 如何防止表单重复提交 - 使用Token,令牌 说到重复提交 ,应该想到两种场景: 1. 在下单,或者支付 这种情况 那么不允许  刷新,不允许后退再点击提交。 2. 在填写表单之后,...
  • u011042188
  • u011042188
  • 2015年09月20日 14:29
  • 13236

使用struts的同步令牌避免form的重复提交

(转载)http://blog.163.com/sky520/blog/static/6845814200812635445832/ (转载)http://www.blogjava.net/patt...
  • sybww
  • sybww
  • 2014年04月11日 13:46
  • 267

使用struts的同步令牌避免form的重复提交

一、使用方法 1、  假如你要提交的页面为toSubmit.jsp; 2、  在打开toSubmit.jsp的Action1中加入:saveToken(request),例如 p...
  • davidin
  • davidin
  • 2013年09月10日 19:46
  • 358

使用struts1和struts2的同步令牌token避免form的重复提交

一、使用方法 1、  假如你要提交的页面为toSubmit.jsp; 2、  在打开toSubmit.jsp的Action1中加入:saveToken(request),例如 p...
  • a441289676
  • a441289676
  • 2013年04月01日 20:26
  • 561

struts的令牌机制,防止重复提交

  • 2009年09月21日 01:50
  • 7KB
  • 下载

struts令牌机制防止重复提交 savetoken(request) resetToken(request)

在web开发中,常会遇到这样的问题:点击了页面的提交按钮了之后,数据保存进数据库,之后按F5刷新页面,又产生了一条同样的数据。解决方法:struts令牌机制。 struts令牌的原理很简单:在进入页...
  • wangyinbin
  • wangyinbin
  • 2012年09月06日 11:32
  • 1066

Struts的Token(令牌)机制解决表单重复提交的问题

Struts的Token(令牌)机制能够很好的解决表单重复提交的问题,基本原理是:服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求...
  • debugingstudy
  • debugingstudy
  • 2013年08月24日 00:04
  • 1481

struts1的令牌解决页面重复提交问题

  • 2013年03月18日 14:34
  • 1.3MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用struts的同步令牌机制避免form的重复提交
举报原因:
原因补充:

(最多只允许输入30个字)