java防止表单二次提交_防止表单重复提交
在Web开发中表单的重复提交是很严重的问题,重复提交成功会产生垃圾数据消耗不必要的资源,更严重的是如果遇到恶意刷库的情况垃圾数据更是数不胜数。在正常使用过程中产生重复提交的情况也有多重情况:鼠标连击、回退提交、刷新提交、网络延迟用户重复提交等。
防止重复提交的方法分两大类就是客户端、服务端(这是废话了)。客户端主要是用js对按钮的限制,一次点击后屏蔽按钮或者是直接跳转等待页面,服务端思路为客户端加token进行验证。客户端就不做详细介绍,主要介绍服务端的控制。
1、客户端存储
就是在客户端不同的地方存储两个token,在服务端进行校验。在Form表单中存储一个token利用隐藏域,在Cookie中存储一个(也可以都放到form表单中两个不同的隐藏域)。档form表单提交的时候,对这两个token进行验证,相同则允许提交否则阻止提交。
优点:
不占用服务器资源
实施起来简单,易上手
缺点:
容易伪造(防君子不防小人)
占用网络资源(或许不是那么明显)
详细介绍一下客户端分布存储在Form表单中和Cookie中的情况。
客户端的实现如下:
packagecn.simple.token;importjavax.servlet.http.Cookie;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.commons.lang.StringUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;/*** 双客户端验证
*@authorldm
* @Date 2016年6月16日*/@Service("clientTokenProcesser")public class ClientTokenProcesser extendsTokenProcesser {
@Autowired
HttpServletResponse response;
@Overridepublic booleanvalidToken(HttpServletRequest request) {
String formToken=request.getParameter(getTokenField()).toString();
System.out.println("formToken:"+formToken);if(StringUtils.isEmpty(formToken))
{
printException("表单中没有token");return false;
}
Cookie[] cookies=request.getCookies();if(cookies==null)
{
printException("cookie 中没有token");
}for(Cookie cookie : cookies) {if(cookie.getName().equals(getTokenKey(request)))
{
String cookieValue=cookie.getValue();
System.out.println("cookieToken:"+cookieValue);if(cookieValue.equals(formToken))
{return true;
}
}
}return false;
}private voidprintException(String msg) {
Exception e= newRuntimeException(msg);
e.printStackTrace();
}
@OverridepublicString getTokenKey(HttpServletRequest request) {
String cookieKey= getTokenField() + "_cookie";returncookieKey;
}
@Overridepublic voidsaveToken(HttpServletRequest request) {
String token=MakeToken.getInstance().getToken();
request.setAttribute(getTokenField(), token);if (response == null) {throw new RuntimeException("HttpServletResponse is null");
}
Cookie cookie= newCookie(getTokenKey(request), token);
response.addCookie(cookie);
}
@OverridepublicString getClientToken(HttpServletRequest request) {
Object token=request.getParameter(getTokenField());if (token == null) {return null;
}else{returntoken.toString();
}
}
}
View Code
2、双向存储
客户端和服务端的token各自独立存储,客户端存储在Cookie或者Form的隐藏域(放在Form隐藏域中的时候,需要每个表单)中,服务端存储在Session(单机系统中可以使用)或者其他缓存系统(分布式系统可以使用)中。
优点:
安全性高(几乎是无法伪造的)
网络资源相对于前者有所减少
缺点:
整个系统实施起来较第一种方法的时候复杂度增加
详细介绍一下服务端存储在session中客户端存储在Cookie中
SessionTokenProcesser实现如下:
packagecn.simple.token;importjavax.servlet.http.Cookie;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.HttpSession;importorg.apache.commons.lang.StringUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;/*** 服务端用Session存储
*
*@authorldm
* @Date 2016年6月16日*/@Service("sessionTokenProcesser")public class SessionTokenProcesser extendsTokenProcesser {
@Autowired
HttpServletResponse response;
@Overridepublic booleanvalidToken(HttpServletRequest request) {
String clientToken=getClientToken(request);if(StringUtils.isEmpty(clientToken)) {return false;
}
HttpSession session= request.getSession(false);if (session == null) {return false;
}
String tokenKey=getTokenKey(request);
Object tokenObj=session.getAttribute(tokenKey);if(tokenObj==null)
{
rethrow("服务端不存在当前token,请重新请求表单");
}
String serverToken=tokenObj.toString();
session.removeAttribute(tokenKey);
System.out.println("remove server token:" +serverToken);returnclientToken.equals(serverToken);
}
@OverridepublicString getTokenKey(HttpServletRequest request) {returngetTokenField();
}
@Overridepublic voidsaveToken(HttpServletRequest request) {
HttpSession session=request.getSession();
String tokenKey=getTokenKey(request);
Object tokenObj=session.getAttribute(tokenKey);
String token;if (tokenObj == null) {
token=MakeToken.getInstance().getToken();//服务端保存token
session.setAttribute(tokenKey, token);
}else{
token=tokenObj.toString();
}
System.out.println("current token:" +token);//写入cookie
Cookie cookie = newCookie(getTokenField(), token);
response.addCookie(cookie);
}private voidrethrow(String message) {
RuntimeException e= newRuntimeException(message);throwe;
}
@OverridepublicString getClientToken(HttpServletRequest request) {
Cookie[] cookies=request.getCookies();if (cookies == null) {
rethrow("没有读取到客户端的cookie");return null;
}for(Cookie cookie : cookies) {if(cookie.getName().equals(getTokenKey(request))) {
String cookieValue=cookie.getValue();returncookieValue;
}
}
rethrow("客户端cookie中没有存储token");return null;
}
}
View Code
java防止表单二次提交_防止表单重复提交相关推荐
- mysql 防重复提交_怎样防止刷新重复提交、防后退
怎样防止刷新重复提交.防后退 提交后禁用提交按钮 1.如果提交后,按F5刷新怎么办? 使用Session 在提交的页面也就是数据库处理之前: if session("ok")=tr ...
- java表单防重复提交_防止表单重复提交的解决方案整理
用户在操作表单Post数据时往往会出现表单数据重复提交的问题,尤其在Web开发中此类问题比较常见.刷新页面,后退操作以前的页面,单机多次按钮都会导致数据重复提交.此类问题是因为浏览器重复提交HTTP请 ...
- 前后端分离重复提交_防止表单重复提交(二)
实现原理: 1.页面和后台同步存入一个token,一旦刷新页面,此token都是会刷新的 2.提交表单时,会带上这个标识token 3.请求后台,将此token和后台存入的token比对 3.1 校验 ...
- python表单防重复提交_防止表单重复提交的几种策略
表单重复提交是在多用户Web应用中最常见.带来很多麻烦的一个问题.有很多的应用场景都会遇到重复提交问题,比如: 点击提交按钮两次. 点击刷新按钮. 使用浏览器后退按钮重复之前的操作,导致重复提交表单. ...
- springboot 订单重复提交_防止表单重复提交(springboot,redis)
我们在web项目中经常需要在后台对用户提交的表单进行校验防止重复提交.下面通过springboot的aop.redis来解决表单重复提交的问题. 通过在controller加上CheckSubmitF ...
- 分布式锁防止订单重复提交_防止表单重复提交看这里!!!
要解决重复提交这事,先要知道什么是重复提交 假如用户的网速慢,用户点击提交按钮,却因为网速慢,而没有跳转到新的页面,这时的用户会再次点击提交按钮,举个例子:用户点击订单页面,当点击提交按钮的时候,也许 ...
- 提交表单数据到数据库_普通表单不仅适用于数据库
提交表单数据到数据库 您也可以将类似的规则应用于数据对象类型. (You can apply similar rules to data object types, too.) You probabl ...
- php ajax jquery 表单重复提交,jQuery如何防止Ajax重复提交
首先说说防止重复点击提交是什么意思. 我们在访问有的网站,输入表单完成以后,单击提交按钮进行提交以后,提交按钮就会变为灰色,用户不能再单击第二次,直到重新加载页面或者跳转.这样,可以一定程度上防止用户 ...
- mysql动态表单设计与实现_动态表单的数据库结构设计
利用在线编辑器设计的表单,包含输入框,明细表(动态添加行)等需要存储到数据库的信息,现在有三种思路: 1.一个表单对应数据库的一张或多张物理表(主从表),这种设计在很多业务的情况下,其数据库的物理表会 ...
最新文章
- 趣AI | 谁说失去手臂就不能弹琴了,有AI啊
- 一个想法照进现实-《IT连》创业项目:直觉型面试招聘的Bug
- @Slf4j注解介绍
- java中创建两种线程的方式_java中创建线程的两种方式有什么区别?
- kubernetes-Pod定义
- SpringCloud Greenwich(七)集成dubbo先启动消费者(check=false),然后启动提供者无法自动发现注册
- 第一太阳能公司(First Solar)在罗斯资本公司的评级上调
- Android 意图和意图过滤器(二)
- nginx日志统计分析的相关常用命
- 使用 APPLY 来为每行调用表值函数
- TypeError: can only concatenate list (not “int“) to list
- 一个一本正经的科普--5G是什么?
- 【Windows系统】产品ID、设备ID等系统参数
- Android 样式系统 | 常见的主题背景属性
- 【原创纯手打】如何使用Vue写微信朋友圈中的留言回复功能(附源码)
- C#笔试题面试题锦集
- 嵌入式linux内核启动过程,嵌入式Linux:ARM Linux启动流程
- linux下贪吃蛇代码,贪吃蛇 linux 程序
- 短信防火墙使用教程(短信防轰炸、防盗刷)
- Google Earth Engine(GEE)——User memory limit exceeded(2)