token機制詳解
注:文內關於使用驗證碼圖片的代碼請參考我的另一篇博客
java Web項目中導入驗證碼圖片功能步驟詳解
重複提交的危害
1)數據庫可能會多次保存相同數據
2)安全問題,如多次支付等
3)服務器性能受損
重複提交的幾種情況
1)成功提交後,直接刷新頁面(每一次刷新就是重複上一次請求)
解決方案:將轉發改爲重定向即可
2)由於網速或服務器的性能,導致處理請求滿,用戶重複點擊註冊等提交表單按鈕
解決方案:將提交按鈕點擊後設爲不可用。然後手動提交表單
js頁面代碼:
<script type="text/javascript">
window.onload=function(){
var btn=document.getElementById("subId");
btn.onclick=function(){
//將按鈕設爲不可點後 提交表單的動作被覆蓋了
//所以我們需要手動提交表單
this.disabled=true;
//提交表單
var formEle=doucument.getElementById("form");
formEle.submit();
};
};
</script>
3)用戶點擊後退按鈕,再次提交
解決方案:由於http爲無狀態協議,瀏覽器無法分辨提交的請求是否上次已經提交過,所以我們在這裏引入token的概念,通過token來判斷是否重複提交
每次提交表單,帶上token令牌,服務器驗證口令是否和我們在session域中取出的一致,一致則爲合法請求,不一致則打回請求
3.1)在session域中設置uuid
<%
//產生一個唯一不重複的令牌當作token
String uuid= UUID.randomUUID().toString();
//放入session域中方便服務器驗證
session.setAttribute("token", uuid);
%>
3.2)在表單提交時帶上值爲uuid的token參數
<form action="login" id="form">
<label>用戶名稱:</label>
<input type="text" name="username" value="">
<br> <br>
<label>用戶密碼:</label>
<input type="password" name="pwd" value="">
<br> <br>
<label>驗證碼:</label>
<input type="text" style="width: 120px;" name="code"/>
<img alt="" src="code.jpg" height="29px" width="70px" id="codeImg">
<input type="text" name="token" value=<%=uuid %>>
<input type="submit" value="登錄" id="subId">
</form>
3.3)在servlet中接受用戶提交時取出session域中存放的token和表單中帶來的token
String token=request.getParameter("token");
HttpSession session = request.getSession();
String tokenSession = (String) session.getAttribute("token");
//從session中取出token後將域中token重新賦值
session.setAttribute("token", UUID.randomUUID().toString());
if(token.equals(tokenSession)) {
//token相同 合法請求
}else {
//token不相同,打回請求
}
3.3)關於爲什麼這樣編寫後可以防止用戶返回後重新提交及爲何要重新設置session域中token值詳解
用戶第一次點擊登錄,session域和表單提交帶上的token是相同的,servlet接收到請求後會對兩者取出的token進行比較,成功則繼續請求,反之打回請求。
不管成功與否,服務器都會將session域中的token重新設置,而當用戶返回後重新提交,表單中token的值是在緩存中取出的,而session域中的token已經是在servlet中被重新賦值了的,兩個自然不同,請求被認定爲非法請求,直接打回