使用struts同步令牌机制避免表单的重复提交

一、使用方法

1、假设你要提交的叶面为usermesg.jsp。

2、在打开usermesg.jsp的SaveTokenAction中加入saveToken(request),源码如下:

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

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;


public class SaveToken extends Action ...{

    /**//* forward name="usermesg" path="/usermesg.jsp" */
    private final static String USERMESG = "usermesg";

    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception ...{
       
         // 在session中放入同步令牌
        saveToken(request);

        // TODO process request and return an ActionForward instance, for example:
        // return mapping.findForward(USERMESG);
        return mapping.findForward(USERMESG);
    }
}
3、在叶面提交的ValidatorAction中加入isTokenValid(request,true)源码如下:

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

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class Validator extends Action ...{
    private final static String ERROR="error";
    private final static String WELCOME="welcome";
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception ...{
       
         // 验证同步令牌
        if(isTokenValid(request,true))...{
            return mapping.findForward(WELCOME);
        }else...{
            return mapping.findForward(ERROR);
        }
        // TODO process request and return an ActionForward instance, for example:
        // return mapping.findForward("forward_name");
    }
}
4、  使用注意:usermesg.jsp中的form表单必须使用struts的标签<html:form>

二、基本原理

1、在session中放入同步令牌。原理:调用TokenProcessor类的saveToken(HttpServletRequest arg0);源码如下:

在sesssion中放入名称为Globale.TRANSACTION_TOKEN_KEY的同步令牌:token

          public synchronized void saveToken(HttpServletRequest request)...{
            HttpSession session=request.getSession();
            String token=generateToken(request);
            if(token!=null)...{
               session.setAttribute(Globale.TRANSACTION_TOKEN_KEY,token);
            }
         }

2、在打开usermesg.jsp时,应用服务器遇到<html:form>时,便会调用FormTag类的renderToken()方法创建hidden元素。源码如下:

protected String renderToken()...{
               StringBuffer result=new StringBuffer();
               HttpSession session=pageContext.getSession();
               if(session!=null)...{
                  String token=(String)session.getAttribute(Globale.TRANSACTION_TOKEN_KEY);
                  if(token!=null)...{
                    result.append("<input type="hidden" name="");
                    result.append(Constants.TOKEN_KEY);
                    result.append("" value="");
                    result.append(token);
                    if(this.isXhtml)...{
                      result.append("" />");
                    }else...{
                      result.append("" >");
                    }
                  }
               }
               return result.toStriong();
         }
hidden元素Constants.TOKEN_KEY的值就是session中的名称为Globale.TRANSACTION_TOKEN_KEY的同步令牌值

3、验证同步令牌,原理:调用TokenProcessor的isTokenValid(HttpServletRequest arg0,boolean arg1)源码如下:

public synchronized boolean isTokenValid(HttpServletRequest request,boolean reset)...{
            HttpSession session request.getSession(false);
            if(session==null) return false;
           
            String saved=(String)session.getAttribute(Globale.TRANSACTION_TOKEN_KEY);
           
            if(saved==null) return false;
           
            if(reset) this.resetToken(request);


            String token=request.getParameter(Constants.TOKEN_KEY);
            
             if(token==null) return false;
            
             return saved.equals(token);
          }
从叶面取出同步令牌值和session中的进行比较。如果相等则为第一次,不等就是重复提交。前提就是传进来的参数reset必须是true。不然每次都相同。其中resetToken()方法如下:

                public synchronized void resetToken(HttpServletRequest request)...{
                    HttpSession session request.getSession(false);
                    if(session==null)...{
                      return;
                    }
                    session.removeAttribute(Globale.TRANSACTION_TOKEN_KEY);
                }
这就是在isTokenValid方法中boolean参数的作用:清除session中的同步令牌,避免重复提交。如果把true改为false 将不会起到避免重复提交的作用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值