1. 程式人生 > >session案例:防止表單重複提交、一次性校驗碼

session案例:防止表單重複提交、一次性校驗碼

session案例1:防止表單重複提交

原理:
	1,表單頁面由servlet程式生成,servlet為每次產生的表單頁面分配一個唯一的隨機標識號,並在FORM表單的一個隱藏欄位中設定這個標識號,同時在當前使用者的Session域中儲存這個標識號。
	2,當用戶提交FORM表單時,負責處理表單提交的serlvet得到表單提交的標識號,並與session中儲存的標識號比較,如果相同則處理表單提交,處理完後清除當前使用者的Session域中儲存的標識號。
	3,在下列情況下,伺服器程式將拒絕使用者提交的表單請求:
		當前使用者的Session中不存在表單標識號
		使用者提交的表單資料中沒有標識號欄位
		儲存Session域中的表單標識號與表單提交的標識號不同

設計:
	// 生成介面,生成一個隨機的唯一的隨機標識號(令牌token)
	RegistUIServlet 實現功能:
		1,把token存放到HttpSession中
		2,提供一個含有type=hidden的輸入表單

	// 處理資料
	RegistServlet 實現功能:
		1,獲取表單提交上來的令牌token
		2,獲取HttpSession中存的令牌

	通過比對錶單提交上來的token的值和HttpSession中token的值來判斷是否為重複提交:
		若二者相等,則:
			1,進行真正的資料處理(業務處理)
			2,刪除HttpSession中儲存的token
		若二者不相等時,則:說明是重複提交的表單

	【注意】
		1,重新整理或重複提交時,只是提交了表單,並沒有再往session中存token。即:重新整理或重複提交僅僅是重新傳遞了token。
		2,在第一次提交後,RegistServlet就把session中的token就被清除了。所以在重複提交時,session中並沒有token,故二者肯定不相等了。

	-----------------------------------------------------

	// 處理註冊的請求,同時判斷是否是重複提交
	public class RegistServlet extends HttpServlet {

		public void doGet(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
			response.setContentType("text/html;charset=UTF-8");
			PrintWriter out = response.getWriter();
			request.setCharacterEncoding("UTF-8");
			String name = request.getParameter("name");
			
			try {
				Thread.sleep(2000);//模擬一下網路的延遲
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			//判斷使用者是否重複提交
			String formToken = request.getParameter("token");
			String sessionToken = (String) request.getSession().getAttribute("token");
			if(formToken.equals(sessionToken)){
				//正常提交
				System.out.println("儲存了:"+name);
				request.getSession().removeAttribute("token");
			}else{
				out.write("請不要重複提交");
			}		
		}

		public void doPost(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
			doGet(request, response);
		}
	}

	---------------------

	//生成註冊頁面
	public class RegistUIServlet extends HttpServlet {

		public void doGet(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
			response.setContentType("text/html;charset=UTF-8");
			PrintWriter out = response.getWriter();
			
			//生成一個隨機的令牌
			String token = ""+System.currentTimeMillis()+new Random().nextLong();
			//算資料指紋,用MD5演算法
			token = MD5Util.md5(token);
			
			// 或者使用UUID生成一個隨機的令牌
			//String token = UUID.randomUUID().toString();//唯一的一段序列
			
			//放入HttpSession中
			request.getSession().setAttribute("token", token);
			
			out.write("<form id='f1' action='"+request.getContextPath()+"/servlet/RegistServlet' method='post'>");
			out.write("姓名:<input type='text' name='name'/><br/>");
			out.write("<input type='hidden' name='token' value='"+token+"'/>");
			out.write("<input id='bt1' type='button' value='註冊' onclick='toSubmit()'/></form>");
			// 在客戶端防止重複提交,但是不能防止重新整理
			out.write("<script type='text/javascript'>function toSubmit(){document.getElementById('f1').submit();document.getElementById('bt1').disabled=true;}</script>");
		}

		public void doPost(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
			doGet(request, response);
		}

	}



session案例2:一次性校驗碼
	目的:一次性驗證碼的主要目的就是為了限制人們利用工具軟體來暴力猜測密碼。 
	原理:
		1,伺服器程式接收到表單資料後,首先判斷使用者是否填寫了正確的驗證碼,只有該驗證碼與伺服器端儲存的驗證碼匹配時,伺服器程式才開始正常的表單處理流程。 
		2,密碼猜測工具要逐一嘗試每個密碼的前題條件是先輸入正確的驗證碼,而驗證碼是一次性有效的,這樣基本上就阻斷了密碼猜測工具的自動地處理過程。