struts2令牌機制

利用Struts同步令牌(Token)機制來解決Web應用中的重複提交問題。該方法的基本原理是:服務器端在處理到達的request之前,會將request中的Token值與保存在當前用戶session中的令牌值進行比較,看是否匹配。在處理完該request後,且在response發送給客戶端之前,將會產生一個新的 Token,該Token除傳給客戶端以外,也會將用戶session中保存的舊的Token進行替換。這樣,如果用戶會退到剛纔的提交頁面並再次提交的話,客戶端傳過來的Token值和服務器端的不一致,從而有效地防止了重複提交地發生。

  struts的Token機制實際上就是通過用戶提交表單時,比較request中的請求參數“org.apache.struts.taglib.html.TOKEN”的值與當前會話中的屬"org.apache.struts.action.TOKEN"的值是否相等,相等則是正常提交,不等則爲重複提交。

   下面我們看下一個完整的操作流程,這樣便於理解:
   首先我們要明白,重複提交是發生在什麼情況下的,什麼情況下需要處理重複提交。我們所要解決的重複提交一般是考慮用戶新插入一條記錄的情形,對於修改記錄的重複提交一般不考慮,因爲修改記錄本身記錄就存在ID,重複提交也只不過是重複更新數據庫同一記錄而已,對數據的正確性不會有影響。如果新插入一條記錄不對重複提交進行處理的話,那麼就會在數據庫中重複插入同一記錄,這樣會在數據庫產生冗餘的重複記錄。當我們要插入一條記錄時,會分二步走。第一步我們要打開新增記錄的頁面。第二步,我們會在打開的頁面中填寫相關信息,然後提交,這個時候提交纔算完成。
第一步:假如我們打開新增記錄這個操作由add方法完成,代碼如下:
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");

第二步:假如我們提交這個頁面數據由save方法完成,代碼如下:
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;
        }
2.然後再判斷當前會話中是否存在令牌屬性"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");

當用戶重複提交時,我說了"this.saveToken(request);//此方法在這裏可要也可不要。",下面我們分

析下,如果不調用這個方法,會話中就不會再重新保存token值,那麼再刷新的時候,session中的token
值總是爲null,isTokenValid(request)直接返回false,如果調用this.saveToken(request)的話,

session中會重新添加token屬性值。這個時候isTokenValid(request)會進行下面第三步的判斷。
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>裏面生成隱含表單,最終的結果都是"重複提交".

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章