过滤器限流,接口防刷,线程安全

因为这个涉及到公司安全漏洞,确实很大隐患,情况描述就抽象一些
情景描述:我们项目中一个很重要的接口,条件限制全部通过是操作redis的读写,与服务器上配置表数据进行判断比较。
因为这个接口很重要,也很敏感。刚好最近在摸索JMEMTER的使用,心想刚好可以测试下,并发的访问下我这个接口,我们的限制能够生效嘛?(这个疑问之前就想过,我们的redis读写操作,不具有原子性。但是我们老大告诉我,Redis的操作很快,不会出现限制不住的问题)
过滤器限流,接口防刷,线程安全
2千个并发,100~200多个请求都没有限制住。

解决思路

我想到三种方式

  1. 接口的最前面,用ConcurrentHashMap 做一个计时器。同一用户不能在多少秒内重复访问
  2. 拦截器的方式
  3. 过滤器的方式
    因为我们的限制条件都在Redis上,在线上环境已经出现过几次问题,导致我们的限制也没有生效。我思考解决问题的方式时,就避开了再用Redis。
    结合我项目的结构,最后我选择了使用过滤器的方式。
过滤器+ConcurrentHashMap 接口限流

我讲过滤器的代码贴上

**
 * @Author yjc
 * @Date 2020/6/6 10:01
 */
public class MyFilter implements Filter {

  	protected Logger log = Logger.getLogger(MyFilter.class);
    private static final long SECOND = 1000;
    /**
     * 用户访问的时间
     */
    private ConcurrentHashMap<String,Long> userVisitTime = new ConcurrentHashMap<>(16);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)  {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
         /**
         * 用户的唯一标识
         */
        String key = request.getParameter("userId");
        try{
            Long lastTime = userVisitTime.get(key);
            if (lastTime != null && lastTime+SECOND <= System.currentTimeMillis()){
                userVisitTime.put(key, System.currentTimeMillis());
                filterChain.doFilter(servletRequest,servletResponse);
            }else if (lastTime == null){
                userVisitTime.put(key, System.currentTimeMillis());
                filterChain.doFilter(servletRequest,servletResponse);
            }
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
    }

    @Override
    public void destroy() {

    }
}

同时还需要再web.xml添加上,我只做了这个重要接口的限制

	<filter>
        <filter-name>myFileter</filter-name>
        <filter-class>com.mini.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>myFileter</filter-name>
        <url-pattern>/data/xx.action</url-pattern>
    </filter-mapping>

下面给大家测试一下,同样的2000个并发,我接口的开始打印了消息,下面是测试结果
过滤器限流,接口防刷,线程安全

设计缺陷

当然这样设计也有很大的问题,如果用户量达到100w,这个ConcurrentHashMap内存占用会不断增大。

还请各位大佬,提出批评指正!

上一篇:为何实现了 Filter 的类,能自动添加到 filterChain 中?


下一篇:Python - Django - 模板语言之自定义过滤器