zoukankan      html  css  js  c++  java
  • SpringBoot之接口防刷限制

    接口防刷代码,思路同样适用防止表单重复提交

    注解:

    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    
    /**
     * 限制接口访问
     */
    @Retention(RUNTIME)
    @Target(METHOD)
    public @interface AccessLimit {
        /**
         * 秒
         * @return
         */
        int seconds();
    
        /**
         * 最大请求数量
         * @return
         */
        int maxCount();
    
        /**
         * 是否需要登录
         * @return
         */
        boolean needLogin() default true;
    
    }

    拦截器逻辑:

    import com.alibaba.fastjson.JSON;
    import com.emi2c.mybatis.config.annotation.AccessLimit;
    import com.emi2c.mybatis.util.RedisUtil;
    import com.emi2c.mybatis.util.ResultUtil;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.OutputStream;
    import java.util.Map;
    import java.util.Objects;
    
    @Component
    public class AccessInterceptor extends HandlerInterceptorAdapter {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        private RedisUtil redisUtil;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            // 判断请求是否属于方法的请求
            if(handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
    
                // 获取方法中的注解,看是否有该注解
                AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);
                if(accessLimit == null) {
                    return true;
                }
    
                // 单位时间
                int seconds = accessLimit.seconds();
                // 访问次数
                int maxCount = accessLimit.maxCount();
                // 是否需要登陆
                boolean needLogin = accessLimit.needLogin();
                String key = request.getRequestURI();
                logger.info("访问地址: {}", key);
                // 是否需要登陆
                if(needLogin) {
                    String username = request.getHeader("username");
                    key = key + "-" + username;
                }
    
                // 已访问次数
                Object o = redisUtil.get(key);
                if(Objects.isNull(o)) {
                    // 第一次访问
                    redisUtil.incr(key, 1);
                    redisUtil.expire(key, seconds);
                } else {
                    // 获取单位时间内已访问次数
                    Integer count = Integer.valueOf(redisUtil.get(key).toString());
                    if(maxCount > count) {
                        // 没超出访问限制
                        redisUtil.incr(key, 1);
                    } else {
                        // 超出访问限制
                        logger.info("访问次数超出限制");
                        Map<String, Object> failure = ResultUtil.getFailure(200, "访问次数超出限制");
                        render(response, failure);
                        return false;
                    }
                }
            }
            return true;
        }
    
    
        /**
         * 封装消息
         * @param response
         * @param message
         * @throws Exception
         */
        private void render(HttpServletResponse response, Map<String, Object> message)throws Exception {
            response.setContentType("application/json;charset=UTF-8");
            OutputStream out = response.getOutputStream();
            String str  = JSON.toJSONString(message);
            out.write(str.getBytes("UTF-8"));
            out.flush();
            out.close();
        }
    
    }

    注册拦截器:

    import com.emi2c.mybatis.config.interceptor.AccessInterceptor;
    import com.emi2c.mybatis.config.interceptor.OperatingInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    //注册拦截器
    @Configuration
    public class WebAppConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //注册自己的拦截器并设置拦截的请求路径
            registry.addInterceptor(getOperatingInterceptor()).addPathPatterns("/**");
            registry.addInterceptor(getAccessInterceptor()).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
    
        /**
         * 解决拦截器内对象注入失败问题
         *
         * @return
         */
        @Bean
        public OperatingInterceptor getOperatingInterceptor() {
            return new OperatingInterceptor();
        }
    
        @Bean
        public AccessInterceptor getAccessInterceptor() {
            return new AccessInterceptor();
        }
    
    }

    注解使用:

    import com.emi2c.mybatis.config.annotation.AccessLimit;
    import com.emi2c.mybatis.util.ResultUtil;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Map;
    
    /**
     * 防刷接口
     */
    @RestController
    public class UnFlushController {
        
    // 5秒内最多允许5次访问 @AccessLimit(maxCount
    = 5, seconds = 5, needLogin = true) @RequestMapping(value = "flush", method = RequestMethod.GET) public Map<String, Object> unFlush() { return ResultUtil.getSuccess(); } }
  • 相关阅读:
    linux安装nginx
    git配置多个SSH密钥
    webpack加载器安装node-sass失败的解决方法
    Vue-cli webpack打包之后index.html缺少引号的问题
    算法:一个数组中所有元素的最小公倍数
    JS 实现一个睡眠函数sleep
    剑指offer 牛客67道题集合
    剑指offer
    剑指offer
    剑指offer
  • 原文地址:https://www.cnblogs.com/mxh-java/p/14400396.html
Copyright © 2011-2022 走看看