今天在做自己的项目的时候,发现有很多的前段插件都自带了防止表单重复提交的功能,例如:ValidForm就提供了这个功能。但是前段的一些插件总是不太安全。
下面直接上代码:
1.创建Token注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
boolean save() default false;
boolean remove() default false;
}
2.继承了SpringMVC的拦截器,并实现其PreHandle方法。
public class TokenInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod) {
// Spring提供的Handler 方便获取类的属性
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取方法
Method method = handlerMethod.getMethod();
// 获取该方法的Token注解
Token token = method.getAnnotation(Token.class);
// 判断是否有Token
if (token != null) {
// 是否保存在Session中
boolean needSaveSession = token.save();
//
if (needSaveSession) {
// 设置token
request.getSession().setAttribute("token", UUID.randomUUID().toString());
}
//判断是否需要验证重复提交
boolean needRemoveSession = token.remove();
//
if (needRemoveSession) {
//验证失败处理
if (isRequestSubmit(request)) {
// response.sendError(500, JSON.toJSONString(new
// Status(500, "请勿重复提交")));
response.setCharacterEncoding("utf-8");
response.getWriter().write(JSON.toJSONString(new Status(500, "请勿重复提交!")));
return false;
}
request.getSession().removeAttribute("token");
}
}
return true;
} else {
return super.preHandle(request, response, handler);
}
}
private boolean isRequestSubmit(HttpServletRequest request) {
String clinetToken = request.getParameter("token");
String serverToken = (String) request.getSession().getAttribute("token");
if (serverToken == null) {
return true;
}
if (clinetToken == null) {
return true;
}
if (!serverToken.equals(clinetToken)) {
return true;
}
return false;
}
}
3.配置在SpringMVC的配置文件里面。
<!-- 拦截器 -->
<mvc:interceptors>
<bean class="com.lls.interceptor.TokenInterceptor" />
</mvc:interceptors>
以上就完成了。使用的时候在需要生成Token的地方加上@Token(save=true).在需要验证重复提交的地方加上@Token(remove=true)就行了。
代码不多很简单,所以还有很多地方时值得优化的。