• springboot 自定义拦截器 防止恶意请求


    该例子需要用到 redis 

    在applocation.properties中加入redis的配置信息

    server.port=8030

    # Redis数据库索引(默认为0)
    spring.redis.database=0
    # Redis服务器地址
    spring.redis.host=localhost
    # Redis服务器连接端口
    spring.redis.port=6379
    # Redis服务器连接密码(默认为空)
    spring.redis.password=
    #连接池最大连接数(使用负值表示没有限制)
    spring.redis.jedis.pool.max-idle=8
    # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.jedis.pool.max-wait=
    # 连接池中的最大空闲连接
    spring.redis.jedis..pool.max-idle=8
    # 连接池中的最小空闲连接
    spring.redis.jedis.pool.min-idle=0
    # 连接超时时间(毫秒)
    spring.redis.timeout=300
     

    RedisConfig.java

    package cn.rc.config;
    
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    @Configuration
    @EnableCaching // 开启注解
    public class RedisConfig extends CachingConfigurerSupport {
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            // 配置连接工厂
            template.setConnectionFactory(factory);
    
            // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
            Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
    
            ObjectMapper om = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jacksonSeial.setObjectMapper(om);
    
            // 值采用json序列化
            template.setValueSerializer(jacksonSeial);
            // 使用StringRedisSerializer来序列化和反序列化redis的key值
            template.setKeySerializer(new StringRedisSerializer());
    
            // 设置hash key 和value序列化模式
            template.setHashKeySerializer(new StringRedisSerializer());
            template.setHashValueSerializer(jacksonSeial);
            template.afterPropertiesSet();
    
            return template;
        }
    }

    需要先启动redis功能

    一、声明一个自定义的注解类

    AccessLimit.java
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface AccessLimit {
        int seconds();
        int maxCount();
        boolean needLogin() default true;
    }

    二、声明一个自定义的拦截器:

    AccessLimtInterceptor.java 

    @Component
    public class AccessLimtInterceptor implements HandlerInterceptor {
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            if (handler instanceof HandlerMethod) {
                HandlerMethod hm = (HandlerMethod) handler;
                AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
                if (null == accessLimit) {
                    return true;
                }
                int seconds = accessLimit.seconds();
                int maxCount = accessLimit.maxCount();
                boolean needLogin = accessLimit.needLogin();
    
                if (needLogin) {
                    //判断是否登录
                }
                String ip=request.getRemoteAddr();
                String key = request.getServletPath() + ":" + ip ;
                Integer count = (Integer) redisTemplate.opsForValue().get(key);
    
                if (null == count || -1 == count) {
                    redisTemplate.opsForValue().set(key, 1,seconds, TimeUnit.SECONDS);
                    return true;
                }
    
                if (count < maxCount) {
                    count = count+1;
                    redisTemplate.opsForValue().set(key, count,0);
                    return true;
                }
    
                if (count >= maxCount) {
    //                response 返回 json 请求过于频繁请稍后再试
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/json; charset=utf-8");
                    JsonResponse  result = new JsonResponse<>();
                    result.setCode(9999);
                    result.setMessage("操作过于频繁");
                    Object obj = JSONObject.toJSON(result);
                    response.getWriter().write(JSONObject.toJSONString(obj));
                    return false;
                }
            }
    
            return true;
        }
    }

    将 拦截器 注册到容器:WebMvcConfig.java

    /**
     * MVC 设置
     *
     */
    @Configuration
    public class WebMvcConfig extends WebMvcConfigurerAdapter {
        @Autowired
        private AccessLimtInterceptor accessLimtInterceptor;
        @Bean
        public AccessTokenVerifyInterceptor tokenVerifyInterceptor() {
            return new AccessTokenVerifyInterceptor();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(accessLimtInterceptor);
            registry.addInterceptor(tokenVerifyInterceptor()).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
    
    }

    进行测试接口:

    使用 @AccessLimit(seconds = 15, maxCount = 3)  注解 修饰接口 , 15秒 只允许访问3次

    @RestController
    @RequestMapping("test")
    public class TestAccessLimitController {
    
        @GetMapping("accessLimit")
        @AccessLimit(seconds = 15, maxCount = 3) //15秒内 允许请求3次
        public String testAccessLimit() {
    
            return "success";
        }
    }

    浏览器请求:http://localhost:8030/test/accessLimit

      返回: success 

    快速刷新多次后出现:

      

  • 相关阅读:
    jquery判断设备是否是手机
    jQuery -- touch事件之滑动判断(左右上下方向)
    sass制作雪碧图
    js时间字符串转为标准时间
    装箱和拆箱
    Dictionary泛型集合实现山寨版金山词霸
    泛型集合
    ArrayList集合与索引器及Hashtable
    黑马程序员--静态方法和静态类
    黑马程序员--多态练习(手机工厂)
  • 原文地址:https://www.cnblogs.com/wanjun-top/p/12974538.html
Copyright © 2020-2023  润新知