利用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(); 
    } 

}

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

相关文章推荐

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

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

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

一、使用方法 1、  假如你要提交的页面为toSubmit.jsp; 2、  在打开toSubmit.jsp的Action1中加入:saveToken(request),例如 p...

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

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

JSP、Struts避免Form重复提交的几种方案

1 javascript ,设置一个变量,只允许提交一次。 2 还是javascript,将提交按钮或者image置为disable onsubmit=“getElById(‘submit...
  • vipyhd
  • vipyhd
  • 2012年06月04日 09:43
  • 165

基于struts2的令牌拦截器,防止表单重复提交

* 在页面中增加一个隐藏域,该隐藏域一定要放到form表单内: 其原理为,当生成页面之后,会生成一个隐藏域 该隐藏域的值第一次提交时会存在session中,再次提交时,与session中的stru...

利用struts的Token机制解决重复提交问题的分析

struts的Token机制实际上就是通过用户提交表单时,比较request中的请求参数“org.apache.struts.taglib.html.TOKEN”的值与当前会话中的属"org.apac...
  • jingken
  • jingken
  • 2011年12月07日 11:16
  • 161

struts+token机制解决表单重复提交

  • 2012年06月21日 12:22
  • 1.25MB
  • 下载

struts token机制解决表单重复提交

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

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