package com.yoro.core.web; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; /** * 防止表单重复提交 FORM TOKEN 过滤器 作用:1.防止用户后退操作,2.防止用户重复刷新操作 * <li> * 利用TOKEN 防止重复提交需要结合特定场景,不要随意乱用 * 1.有写业务是允许用户插入重复数据的,没必要使用 * 2.有些业务是有状态控制的 重复提交有引发业务及验证 也没必要使用 * 3.如类是于淘宝下单业务是不允许通过一个form 重复提交下单的 则可以利用token实现 * <li> * 使用注意: * <li> * 1.如果结合springmvc 等其他mvc框架 使用 注意 addUrl 路径 不能 和 validUrl 路径 相同 * 只通过 get | post 提交方式区分调用的 action method 否则 点击后退安全不会读取浏览器缓存 * </li> * @author zoro */ public class XsrfTokenRequestFilter implements Filter { /** * addUrls ,validUrls , processUrls 三个数组长度必须相等一一对应 */ private String[] addUrls; // 需要增加 TOKEN 的页面 private String[] validUrls;// 需要验证TOEKN 的页面 private String[] processUrls; // TOKEN 验证失败处理的页面 FilterConfig filterConfig = null; public void init(FilterConfig filterConfig) throws ServletException { // 传入的参数分割符号 String splitChar = filterConfig.getInitParameter("splitChar"); if (StringUtils.isNotBlank(filterConfig.getInitParameter("addUrls"))) { addUrls = filterConfig.getInitParameter("addUrls").split(splitChar); } if (StringUtils.isNotBlank(filterConfig.getInitParameter("validUrls"))) { validUrls = filterConfig.getInitParameter("validUrls").split( splitChar); } if (StringUtils .isNotBlank(filterConfig.getInitParameter("processUrls"))) { processUrls = filterConfig.getInitParameter("processUrls").split( splitChar); } this.filterConfig = filterConfig; } public void destroy() { this.filterConfig = null; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 获取请求路径 String path = getRelativePath((HttpServletRequest) request); // 如果路径存在增加的urls列表里面,则向客户端增加一个token 参数 if (ArrayUtils.contains(addUrls, path)) { xsrfTokenGenerator.save((HttpServletRequest) request, (HttpServletResponse) response); } // 如果路径存在验证urls列表里面 这获取客户端 token 参数做验证 if (ArrayUtils.contains(validUrls, path)) { if (!xsrfTokenGenerator.validate((HttpServletRequest) request, (HttpServletResponse) response)) { // 验证没有通过则跳转到错误处理页面 ((HttpServletResponse) response) .sendRedirect(processUrls[ArrayUtils.indexOf(validUrls, path)]); return; } } // 到了这里说明验证已经通过,则将客户端 token 删除 下次提交客户端cookie token 为空 重复提交则失败 if (ArrayUtils.contains(validUrls, path)) { xsrfTokenGenerator.remove((HttpServletRequest) request, (HttpServletResponse) response); } chain.doFilter(request, response); } protected String getRelativePath(HttpServletRequest request) { if (request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null) { String result = (String) request .getAttribute(RequestDispatcher.INCLUDE_PATH_INFO); if (result == null) { result = (String) request .getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); } else { result = (String) request .getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH) + result; } if ((result == null) || (result.equals(""))) { result = "/"; } return (result); } // No, extract the desired path directly from the request String result = request.getPathInfo(); if (result == null) { result = request.getServletPath(); } else { result = request.getServletPath() + result; } if ((result == null) || (result.equals(""))) { result = "/"; } return (result); } // 实例化 token 生成器 private XsrfTokenGenerator xsrfTokenGenerator = new SimpleXsrfTokenGenerator(); }
package com.yoro.core.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public interface XsrfTokenGenerator { /** * 增加 TOKEN */ public String save(HttpServletRequest request, HttpServletResponse response); /** * 删除TOKEN */ public void remove(HttpServletRequest request, HttpServletResponse response); /** * 验证TOKEN 是否有效 验证成功应当手动调用 remove 方法 手动从COOKIE中清除TOKEN */ public boolean validate(HttpServletRequest request, HttpServletResponse response); }
package com.yoro.core.web; import java.util.UUID; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import com.common.web.CookieUtils; /** * * 基于cookie 的 利用TOOKEN 防止表单重复提交的实现 * * @author zoro * */ public class SimpleXsrfTokenGenerator implements XsrfTokenGenerator { /** * 默认TOOKEN 名称 */ private final static String FORM_TOEKN_NAME = "_form_token"; @Override public boolean validate(HttpServletRequest request, HttpServletResponse response) { String paramString = request.getParameter(FORM_TOEKN_NAME); if (StringUtils.isBlank(paramString)) { return false; } String value = get(request); if (StringUtils.isBlank(value)) { return false; } return value.equals(paramString); } @Override public String save(HttpServletRequest request, HttpServletResponse response) { String value = StringUtils.remove(UUID.randomUUID().toString(), "-"); if (value != null) { set(request, response, value); } return value; } @Override public void remove(HttpServletRequest request, HttpServletResponse response) { String value = get(request); if (value != null) { cancle(request, response); } } /** * 从cookie中获取TOKEN * * @param request * @return */ private String get(HttpServletRequest request) { Cookie cookie = CookieUtils.getCookie(request, FORM_TOEKN_NAME); return cookie == null ? null : cookie.getValue(); } /** * 设置 TOKEN 到 COOKIE 当中 * * @param request * @param response * @param value */ private void set(HttpServletRequest request, HttpServletResponse response, String value) { if (value != null) { CookieUtils.addCookie(request, response, FORM_TOEKN_NAME, value, -1, null); } if (value != null) { request.setAttribute(FORM_TOEKN_NAME, value); } } /** * 从COOKIE中清楚TOKEN * * @param request * @param response */ private void cancle(HttpServletRequest request, HttpServletResponse response) { CookieUtils.cancleCookie(request, response, FORM_TOEKN_NAME, null); } }
package com.common.web; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.springframework.util.Assert; /** * Cookie 辅助类 * * @author hp * */ public class CookieUtils { /** * 每页条数cookie名称 */ public static final String COOKIE_PAGE_SIZE = "_cookie_page_size"; /** * 默认每页条数 */ public static final int DEFAULT_SIZE = 20; /** * 最大每页条数 */ public static final int MAX_SIZE = 200; /** * 获得cookie的每页条数 * * 使用_cookie_page_size作为cookie name * * @param request * HttpServletRequest * @return default:20 max:200 */ public static int getPageSize(HttpServletRequest request) { Assert.notNull(request); Cookie cookie = getCookie(request, COOKIE_PAGE_SIZE); int count = 0; if (cookie != null) { if (NumberUtils.isDigits(cookie.getValue())) { count = Integer.parseInt(cookie.getValue()); } } if (count <= 0) { count = DEFAULT_SIZE; } else if (count > MAX_SIZE) { count = MAX_SIZE; } return count; } /** * 获得cookie * * @param request * HttpServletRequest * @param name * cookie name * @return if exist return cookie, else return null. */ public static Cookie getCookie(HttpServletRequest request, String name) { Assert.notNull(request); Cookie[] cookies = request.getCookies(); if (cookies != null && cookies.length > 0) { for (Cookie c : cookies) { if (c.getName().equals(name)) { return c; } } } return null; } /** * 根据部署路径,将cookie保存在根目录。 * * @param request * @param response * @param name * @param value * @param expiry * @param domain * @return */ public static Cookie addCookie(HttpServletRequest request, HttpServletResponse response, String name, String value, Integer expiry, String domain) { Cookie cookie = new Cookie(name, value); if (expiry != null) { cookie.setMaxAge(expiry); } if (StringUtils.isNotBlank(domain)) { cookie.setDomain(domain); } String ctx = request.getContextPath(); cookie.setPath(StringUtils.isBlank(ctx) ? "/" : ctx); response.addCookie(cookie); return cookie; } /** * 取消cookie * * @param request * @param response * @param name * @param domain */ public static void cancleCookie(HttpServletRequest request, HttpServletResponse response, String name, String domain) { Cookie cookie = new Cookie(name, ""); cookie.setMaxAge(0); String ctx = request.getContextPath(); cookie.setPath(StringUtils.isBlank(ctx) ? "/" : ctx); if (StringUtils.isNotBlank(domain)) { cookie.setDomain(domain); } response.addCookie(cookie); } }
<!--@分隔 --> <filter> <filter-name>xsrfTokenRequestFilter</filter-name> <filter-class>com.yoro.core.web.XsrfTokenRequestFilter</filter-class> <init-param> <param-name>splitChar</param-name> <param-value>@</param-value> </init-param> <init-param> <param-name>addUrls</param-name> <param-value>/member/forgot_password.html;/login.html</param-value> </init-param> <init-param> <param-name>validUrls</param-name> <param-value>/member/forgot_password.jhtml;/login.jhtml</param-value> </init-param> <init-param> <param-name>processUrls</param-name> <param-value>/member/forgot_password.html;/login.html</param-value> </init-param> </filter> <filter-mapping> <filter-name>xsrfTokenRequestFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
不介意的可以进入我的店铺看下增加点人气
http://qc5z.taobao.com/
相关推荐
struts2防止表单重复提交,利用struts的拦截器tokenSession,轻轻松松解决表单重复提交的问题。 附件为源代码,后台延迟了3秒,可直接在web服务器下部署运行,输入用户名和密码后,多点几次提交按钮,然后看控制台...
防止表单重复提交的方法(简单的token方式),内附实现代码及实现思路。
本文实例讲述了PHP使用token防止表单重复提交的方法。分享给大家供大家参考,具体如下: <?php /* * PHP使用token防止表单重复提交 * 此处理方法纯粹是为了给初学者参考 */ session_start(); function set_token...
利用Token机制解决重复重复提交
JavaEE Struts2利用tokenSession防止重复提交
基于SSM开发框架,使用Token并通过注解和拦截器方式实现表单重复提交验证
本篇文章主要介绍了springMVC中基于token防止表单重复提交方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
自定义封装注解类,(生成token存放到redis中)通过注解的方式解决API接口幂等设计防止表单重复提交
主要讲解了在structs怎样通过Token令牌解决表单重复提交的问题。附带了擦参考项目。
struts token机制解决表单重复提交
主要介绍了PHP实现防止表单重复提交功能,结合实例形式分析了php基于token验证防止表单重复提交的相关操作技巧,非常简单实用,需要的朋友可以参考下
NULL 博文链接:https://minejava.iteye.com/blog/960617
token-springMVC 防止重复提交
详细介绍struts+token机制解决表单重复提交问题。附带相关代码
提供源代码和思想,整体架构都在,只需加入你自己的业务逻辑即可。
这里是Struts2 中放置表单重复提交的例子。
里面包含三种防止表单提交的方法,我这块儿主力推荐的就是token
Token一般用在两个地方——防止表单重复提交、anti csrf攻击(跨站点请求伪造)。 两者在原理上都是通过session token来实现的。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,...
struts2_token控制刷新重复提交