一、使用方法
1、 假如你要提交的頁(yè)面為toSubmit.jsp;
2、 在打開(kāi)toSubmit.jsp的Action1中加入:saveToken(request),例如
public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { //生成同步令牌 saveToken(request); return mapping.findForward("toSubmit"); } |
3、 在提交toSubmit.jsp的Action2中加入:isTokenValid(request, true),例如:
public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // 驗(yàn)證同步令牌 if (isTokenValid(request, true)) { //執(zhí)行提交操作 }else { // 重復(fù)提交 return mapping.findForward("Error"); } } |
4、 使用注意:toSubmit.jsp中的form必須使用struts的標(biāo)簽<html:form>。
二、基本原理
第一步、在session中放入同步令牌
在Action1中加入了saveToken(request)的方法后,調(diào)用TokenProcessor類的saveToken方法如下:
public synchronized void saveToken(HttpServletRequest request) { HttpSession session = request.getSession(); String token = generateToken(request); if (token != null) { session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token); } } |
很明顯在session中放入了同步令牌,名稱為Globals.TRANSACTION_TOKEN_KEY。
第二步、在頁(yè)面創(chuàng)建hidden元素
當(dāng)應(yīng)用服務(wù)器初始化toSubmit.jsp頁(yè)面遇到標(biāo)簽<html:form>時(shí),便會(huì)調(diào)用struts的FormTag類,其中有一個(gè)方法:
protected String renderToken() { StringBuffer results = new StringBuffer(); HttpSession session = pageContext.getSession(); if (session != null) { String token = (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY); if (token != null) { results.append("<input type=\"hidden\" name=\""); results.append(Constants.TOKEN_KEY); results.append("\" value=\""); results.append(token); if (this.isXhtml()) { results.append("\" />"); } else { results.append("\">"); } } } return results.toString(); } |
其意為:當(dāng)檢測(cè)到session中的Globals.TRANSACTION_TOKEN_KEY不為空時(shí),在toSubmit.jsp頁(yè)面創(chuàng)建元素:
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value=""> |
名稱為:org.apache.struts.taglib.html.TOKEN就是Constants.TOKEN_KEY;
值為:session中的Globals.TRANSACTION_TOKEN_KEY的值,即為同步令牌值。
第三步、驗(yàn)證同步令牌
在Action2中加入isTokenValid方法,實(shí)際上是調(diào)用TokenProcessor類的isTokenValid方法如下:
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(Globals.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(Constants.TOKEN_KEY); if (token == null) { return false; } return saved.equals(token); } |
它首先取得session中的令牌值,然后resetToken,再?gòu)捻?yè)面hidden元素取來(lái)令牌值,進(jìn)行比較,如果相等則為第一次,不等則為重復(fù)提交。
其中resetToken方法如下:
public synchronized void resetToken(HttpServletRequest request) { HttpSession session = request.getSession(false); if (session == null) { return; } session.removeAttribute(Globals.TRANSACTION_TOKEN_KEY); } |