通过cookie的方式实现表单重复提交校验

基于springboot+jdk8
本次通过拦截器的方式实现表单重复提交的校验, 可详细交流

注解

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

    boolean verify() default false;
}

拦截器

public class FormTokenInterceptor extends HandlerInterceptorAdapter {


    private final String tokenKey = "_token";

    private CacheClient cacheClient;

    public FormTokenInterceptor() {
        cacheClient = (CacheClientImpl) SpringBeanUtils.getBean("cacheClientImpl");
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            Token annotation = method.getAnnotation(Token.class);
            if (annotation != null) {
                boolean access = true;
                if (annotation.verify()) {
                    access = verifyToken(request);
                }
                generateToken(request, response);
                if (!access) {
                    throw new ApplicationException(MessageUtils.get("message-form-repetition-submit"));
                }
            }
        }
        return true;
    }

    private boolean verifyToken(HttpServletRequest request) {
        // 请求token为空
        String clientToken = getCookieValue(request, tokenKey);
        if (clientToken == null) {
            return false;
        }
        // redis token为空
        String serverToken = cacheClient.get(clientToken);
        // redis token不匹配请求token
        if (!clientToken.equals(serverToken)) {
            return false;
        }
        // 删除redis token
        cacheClient.expire(serverToken, 0);

        return true;
    }

    private String getCookieValue(HttpServletRequest request, String key) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(key)) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }

    private void generateToken(HttpServletRequest request, HttpServletResponse response) {
//        String remoteIpAddress = HttpServletUtils.getRemoteIpAddress(request);
//        String token = remoteIpAddress + "@" + FormToken.generateToken();
        String token = FormToken.generateToken();

        Cookie cookie = new Cookie(tokenKey, token);
        cookie.setMaxAge(7200);
        cookie.setPath("/");
        response.addCookie(cookie);

        cacheClient.set(token, token);
        cacheClient.expire(token, 7200);
    }

}

MVC注册拦截器

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        // 表单重复提交拦截器注册拦截器
        registry.addInterceptor(new FormTokenInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/error")
                .excludePathPatterns(Arrays.asList("/component/**", "/html/**", "/favicon.ico"));

    }
}

使用方式

    在需要校验的上一个接口请求添加此注解,设置生成cookie,并将token存入缓存之中
    @Token

	在需要校验的接口加此注解, 拦截器会校验cookie是否一致,如果不一致不允许提交,无论失败或者成功,都会更新缓存中的token
	@Token(verify = true)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值