spring MVC 后台token防重复提交解决方案

2018-06-18 02:54:32来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

看到公司有个部门提出了这个问题,补个粗略的解决方案。。。

1.编写拦截器

/**
 * Description: 防止重复提交
 *
 * @Author liam
 * @Create Date: 2018/3/9 9:22
 */
public class AvoidReSubmitIntercepter extends HandlerInterceptorAdapter {

    private static final String SPLIT_FLAG = "_";
    private static final String AVOID_RE_SUBMIT_TOKEN_KEY = "identifier_token";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (checkAvoidReSubmitTokenOn(handler,AvoidReSubmitBehavior.Check)) {
            //验证是否重复
            if (checkIsRepeatSubmit(request)) {
                //重复提交
                return false;
            }
        }
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (checkAvoidReSubmitTokenOn(handler,AvoidReSubmitBehavior.Create)) {
            Random random = new Random();
            String uuid = UUID.randomUUID().toString().replace(SPLIT_FLAG, String.valueOf(random.nextInt(100000)));
            String tokenValue = String.valueOf(System.currentTimeMillis());
            String transferToken = uuid + SPLIT_FLAG + tokenValue;
            request.setAttribute(AVOID_RE_SUBMIT_TOKEN_KEY, transferToken);
            request.getSession(true).setAttribute(uuid, tokenValue);
        }
        super.postHandle(request, response, handler, modelAndView);
    }

    /**
    * Description: 是否开启防重规则
    *
    * @Author liam
    * @Create Date: 2018/3/9 10:33
    */
    private boolean checkAvoidReSubmitTokenOn(Object handler,AvoidReSubmitBehavior behavior) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method invokeMethod = handlerMethod.getMethod();
        AvoidReSubmitToken avoidReSubmitToken = invokeMethod.getAnnotation(AvoidReSubmitToken.class);
        if (avoidReSubmitToken != null && avoidReSubmitToken.behavior().equals(behavior)) {
            return true;
        }
        return false;

    }

    private boolean checkIsRepeatSubmit(HttpServletRequest request) {
        String clientToken = request.getParameter(AVOID_RE_SUBMIT_TOKEN_KEY);
        if (StringUtils.isEmpty(clientToken)) {
            clientToken = request.getParameter(AVOID_RE_SUBMIT_TOKEN_KEY);
            if (StringUtils.isEmpty(clientToken)) {
                return true;
            }
        }
        String[] clientTokensDetail = StringUtils.split(clientToken, SPLIT_FLAG);
        if (clientTokensDetail.length == 2) {
            String uuid = clientTokensDetail[0];
            String token = clientTokensDetail[1];
       //此处存在并发风险...阔以加锁处理 String serverToken
= (String) request.getSession(true).getAttribute(uuid); if (StringUtils.isNotEmpty(serverToken) && token.equals(serverToken)) { request.getSession(true).removeAttribute(uuid); return false; } } return true; } }

提供开启规则的注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AvoidReSubmitToken {

    AvoidReSubmitBehavior behavior();

}

定义两种行为:

public enum  AvoidReSubmitBehavior {
    Create,
    Check;
}

拦截器的配置:

<!-- 拦截器配置 -->
    <mvc:interceptors>
        <!-- 配置Token拦截器,防止用户重复提交数据 -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="liam.AvoidReSubmitIntercepter"/>
        </mvc:interceptor>
    </mvc:interceptors>

Java代码使用;

    @AvoidReSubmitToken(behavior = AvoidReSubmitBehavior.Create)
    @RequestMapping("test")
    public String testPage() {
        return "form/page";
    }
    @AvoidReSubmitToken(behavior = AvoidReSubmitBehavior.Check)
    @RequestMapping("potHandler")
    public String postHandler(){
        return "ok";
    }

页面代码:

<form id="" class="form-horizontal" action="${ctx}/postHandler" method="post">
        ......
        <input type="hidden" name="token" value="${identifier_token}"/>
        <!-- 注:name必须是identifier_token -->
        ......
</form>


其实该方案也可以验证提交数据是否有效,当然通常是把token放到只读的缓存了。。

伪代码。。没测试呢。。。

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Hibernate框架的讲解

下一篇:Java web.xml 配置技巧—动态欢迎页地址