springMVC中基于令牌防止表单重复提交方法

  

本文介绍了springMVC中基于令牌防止表单重复提交方法,分享给大家,具体如下:

  

<>强实现思路:

  

在springmvc配置文件中加入拦截器的配置,拦截两类请求,一类是到页面的,一类是提交表单的。当转到页面的请求到来时,生成令牌的名字和标记值,一份放到复述,缓存中,一份放传给页面表单的隐藏域。(注:这里之所以使用复述,缓存,是因为tomcat服务器是集群部署的,要保证令牌的存储介质是全局线程安全的,而复述是单线程的)

  

当表单请求提交时,拦截器得到参数中的tokenName和令牌,然后到缓存中去取令牌值,如果能匹配上,请求就通过,不能匹配上就不通过。这里的tokenName生成时也是随机的,每次请求都不一样。而从缓存中取令牌值时,会立即将其删除(删与读是原子的,无线程安全问题)。

  

<>强实现方式:

  

TokenInterceptor.Java         包com.xxx.www.common.interceptor;      进口java.io.IOException;   进口java.util.HashMap;   进口java.util.Map;   进口javax.servlet.http.HttpServletRequest;   进口javax.servlet.http.HttpServletResponse;   进口org.apache.log4j.Logger;   进口org.springframework.beans.factory.annotation.Autowired;   进口org.springframework.web.servlet.handler.HandlerInterceptorAdapter;   进口com.xxx.cache.redis.IRedisCacheClient;   进口com.xxx.common.utility.JsonUtil;   进口com.xxx.www.common.utils.TokenHelper;/* *   *   * @see TokenHelper   */公共类TokenInterceptor HandlerInterceptorAdapter延伸   {      私有静态日志记录器=Logger.getLogger (TokenInterceptor.class);   私有静态Map<字符串,String>viewUrls=new HashMap<字符串,String> ();   私有静态Map<字符串,String>actionUrls=new HashMap<字符串,String> ();   私有对象时钟=新对象();      @ autowired   私人IRedisCacheClient redisCacheClient;   静态   {   viewUrls。put("/用户/regc/brandregnamecard/?“得到”);   viewUrls。put("/用户/regc/regnamecard/?“得到”);      actionUrls。put("/用户/regc/brandregnamecard/?“后”);   actionUrls。put("/用户/regc/regnamecard/?“后”);   }   {   TokenHelper.setRedisCacheClient (redisCacheClient);   }/* *   *拦截方法,添加或验证令牌   */@Override   公共布尔preHandle (HttpServletRequest请求,HttpServletResponse响应对象处理程序)抛出异常   {   字符串url=request.getRequestURI ();   字符串方法=request.getMethod ();   如果(viewUrls.keySet () .contains (url),,((viewUrls.get (url))==null | | viewUrls.get (url) .equals(方法)))   {   TokenHelper.setToken(请求);   返回true;   }   else if (actionUrls.keySet () .contains (url),,((actionUrls.get (url))==null | | actionUrls.get (url) .equals(方法)))   {   log.debug(“截取调用检查有效的交易令牌。”);   返回handleToken(请求、响应处理程序);   }   返回true;   }      保护布尔handleToken (HttpServletRequest请求,HttpServletResponse响应对象处理程序)抛出异常   {   同步(时钟)   {   如果(! TokenHelper.validToken(请求))   {   System.out.println(“未通过验证…”);   返回handleInvalidToken(请求、响应处理程序);   }   }   System.out.println(“通过验证…”);   返回handleValidToken(请求、响应处理程序);   }/* *   *当出现一个非法令牌时调用   */保护布尔handleInvalidToken (HttpServletRequest请求,HttpServletResponse响应对象处理程序)抛出异常   {   Object> Map<字符串;data=https://www.yisu.com/zixun/new HashMap <字符串、对象> ();   数据。(“国旗”,0);   数据。把(“味精”、“请不要频繁操作!”);   writeMessageUtf8(响应、数据);   返回错误;   }/* *   *当发现一个合法令牌时调用。   */保护布尔handleValidToken (HttpServletRequest请求,HttpServletResponse响应对象处理程序)抛出异常   {   返回true;   }      私人空间writeMessageUtf8 (HttpServletResponse响应,Map<字符串,Object>json)抛出IOException   {   试一试   {   response.setCharacterEncoding (“utf - 8”);   response.getWriter () .print (JsonUtil.toJson (json));   }   最后   {   .close response.getWriter () ();   }   }      }      之前      

TokenHelper.java         包com.xxx.www.common.utils;      进口java.math.BigInteger;   进口java.util.Map;   进口java.util.Random;   进口javax.servlet.http.HttpServletRequest;   进口org.apache.log4j.Logger;   进口com.xxx.cache.redis.IRedisCacheClient;/* *   * TokenHelper   *   */公开课TokenHelper   {/* *   *保存令牌值的默认命名空间   */公共静态最终字符串TOKEN_NAMESPACE=皒xx.tokens”;/* *   *持有标记名称的字段名   */公共静态最终字符串TOKEN_NAME_FIELD=皒xx.token.name”;   私有静态最终记录器日志=Logger.getLogger (TokenHelper.class);   私有静态最终随机随机=new随机();      私有静态IRedisCacheClient redisCacheClient;//缓存调用,代替会话,支持分布式      公共静态孔隙setRedisCacheClient (IRedisCacheClient redisCacheClient)   {   TokenHelper。redisCacheClient=redisCacheClient;   }/* *   *使用随机字串作为象征性的名字保存牌   *   * @param请求   * @return令牌   */公共静态字符串setToken (HttpServletRequest请求)   {   返回setToken(请求,generateGUID ());   }/* *   *使用给定的字串作为象征性的名字保存牌   *   * @param请求   * @param tokenName   * @return令牌   */私有静态字符串setToken (HttpServletRequest请求,字符串tokenName)   {   字符串标记=generateGUID ();   setCacheToken(请求、tokenName令牌);   返回标记;   }/* *   *保存一个给定名字和值的令牌   *   * @param请求   * @param tokenName   * @param令牌   */私有静态孔隙setCacheToken (tokenName HttpServletRequest请求,字符串,字符串标记)   {   试一试   {   字符串tokenName0=buildTokenCacheAttributeName (tokenName);   redisCacheClient。listLpush (tokenName0,令牌);   请求。setAttribute (TOKEN_NAME_FIELD tokenName);   请求。setAttribute (tokenName,令牌);   }   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null

springMVC中基于令牌防止表单重复提交方法