Struts 中的 Token 机制

2017-02-25  本文已影响201人  七弦桐语

背景

在提交表单的时候,通常有一种情况是新增加一条记录。当新增成功的时候,跳到添加成功的界面,如果用户点击了浏览器的回退,转到刚才的提交页面,再次点击提交。此时如果没有做处理,就会发生重复提交的问题。如果新插入一条记录不对重复提交进行处理的话,那么就会在数据库中重复插入同一记录,这样会在数据库产生冗余的重复记录。

Token 机制

Struts中的Token机制,实际上就是通过用户提交表单时,比较request中的请求参数org.apache.struts.taglib.html.TOKEN的值与当前会话中的属org.apache.struts.action.TOKEN的值是否相等,相等则是正常提交,不等则为重复提交。

 if (isTokenValid(request, true)) {
       // 未重复提交时,正确的时候应该做的事情
    return mapping.findForward("success");
} else {
    // 重复提交时,需要做的事情
    saveToken(request);
    return mapping.findForward("error");
} 

处理过程

1. 新增一条记录时

在转到新增界面的action中

public ActionForward add(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response) { 
  this.saveToken(request);//这个方法就是产生令牌值,struts已有的方法 
  return mapping.findForward("add");//返回新增页面
}

通过调用saveToken(request),产生一个token值。(注:每次调用saveToken方法产生的token值都不同)

然后在记录新增页面中的<html:form>内部增加一个隐含表单字段,形式如下:

<div>
  <input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="8b2d950f23b02c527988a14171254025">
</div>

然后再把token值8b2d950f23b02c527988a14171254025保存到当前会话中,也就是 session.setAttribute( "org.apache.struts.action.TOKEN","8b2d950f23b02c527988a14171254025");

2. 提交的数据保存

public ActionForward save(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response) { 
  if (this.isTokenValid(request)) {//正常提交
   //其它业务操作......
   this.resetToken(request);//清空当前会话中的token值
   return mapping.findForward("success");//返回保存成功页面
  } else {//重复提交   
   this.saveToken(request);//注:此方法在这里可要也可不要。  
   return mapping.findForward("fail");//返回重复提交提示信息页面
  }
}

判断是不是重复提交关键是isTokenValid(request)这个方法,这个方法由struts提供,如果返回结果为true则表示正常提交,false则为重复提交。isTokenValid(request)这个方法实际上主要做了三件事,

  1. 判断当前会话是否过期,如果过期,直接返回false
HttpSession session = request.getSession(false);
if (session == null) {
    return false;
}
  1. 然后再判断当前会话中是否存在令牌属性org.apache.struts.action.TOKEN,如果不存在,返回false
String saved =(String) session.getAttribute("org.apache.struts.action.TOKEN");
if (saved == null) {
    return false;
}

为什么令牌属性org.apache.struts.action.TOKEN会不存在呢,那是因为当用户正常提交后,会调用this.resetToken(request);//清空当前会话中的token值。也就是说resetToken(request)方法中调用了 session.removeAttribute("org.apache.struts.action.TOKEN");

3 .从当前会话中取得token的值与当前request中得到的token值比较,相同返回true,不同返回false

String token = request.getParameter("org.apache.struts.taglib.html.TOKEN");
if (token == null) {
    return false;
}
return saved.equals(token);

如果是重复刷新,那么每次request中的令牌值都是一样的,但每次刷新当前会话中的令牌值都被重新替换了,所以会返回false

:使用struts的表单提交Token机制时,提交的表单一定要写成<html:form></html:form>这种形式,如果写成<form></form>这种形式的话,尽管调用saveToken(request)方法也不会在当前的<form></form>里面生成隐含表单,最终的结果都是"重复提交".

上一篇下一篇

猜你喜欢

热点阅读