zoukankan      html  css  js  c++  java
  • springboot过滤器禁止ip频繁访问

    1.编写一个过滤器: 

    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;
    
    @Slf4j
    @WebFilter(urlPatterns="/dyflight/*")
    public class IpFilter implements Filter{
    
        /**
         * 默认限制时间(单位:ms)3600000,3600(s),
         */
        private static final long LIMITED_TIME_MILLIS = 10 * 1000;
    
        /**
         * 用户连续访问最高阀值,超过该值则认定为恶意操作的IP,进行限制
         */
        private static final int LIMIT_NUMBER = 5;
    
        /**
         * 用户访问最小安全时间,在该时间内如果访问次数大于阀值,则记录为恶意IP,否则视为正常访问
         */
        private static final int MIN_SAFE_TIME = 5000;
    
        private FilterConfig config;
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            this.config = filterConfig;    //设置属性filterConfig
        }
    
        /* (non-Javadoc)
         * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
         */
        @SuppressWarnings("unchecked")
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
                throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            ServletContext context = config.getServletContext();
            // 获取限制IP存储器:存储被限制的IP信息
            //Map<String, Long> limitedIpMap = (Map<String, Long>) context.getAttribute("limitedIpMap");
            ConcurrentHashMap<String ,Long> limitedIpMap = (ConcurrentHashMap<String, Long>)  context.getAttribute("limitedIpMap");
            // 过滤受限的IP
            filterLimitedIpMap(limitedIpMap);
            // 获取用户IP
            String ip = IPUtil.getRemoteIpAddr(request);
            System.err.println("ip:"+ip);
            // 判断是否是被限制的IP,如果是则跳到异常页面
            if (isLimitedIP(limitedIpMap, ip)) {
                long limitedTime = limitedIpMap.get(ip) - System.currentTimeMillis();
                // 剩余限制时间(用为从毫秒到秒转化的一定会存在些许误差,但基本可以忽略不计)
                request.setAttribute("remainingTime", ((limitedTime / 1000) + (limitedTime % 1000 > 0 ? 1 : 0)));
                System.err.println("ip访问过于频繁:"+ip);
                throw new RuntimeException("ip访问过于频繁");
            }
            // 获取IP存储器
            ConcurrentHashMap<String, Long[]> ipMap = (ConcurrentHashMap<String, Long[]>) context.getAttribute("ipMap");
            // 判断存储器中是否存在当前IP,如果没有则为初次访问,初始化该ip
            // 如果存在当前ip,则验证当前ip的访问次数
            // 如果大于限制阀值,判断达到阀值的时间,如果不大于[用户访问最小安全时间]则视为恶意访问,跳转到异常页面
            if (ipMap.containsKey(ip)) {
                Long[] ipInfo = ipMap.get(ip);
                ipInfo[0] = ipInfo[0] + 1;
                log.debug("当前第[" + (ipInfo[0]) + "]次访问");
                if (ipInfo[0] > LIMIT_NUMBER) {
                    Long ipAccessTime = ipInfo[1];
                    Long currentTimeMillis = System.currentTimeMillis();
    
                    log.debug("ip访问过于频繁:currentTimeMillis: "+currentTimeMillis+"  - ipAccessTime:"+ipAccessTime+" : " + (currentTimeMillis - ipAccessTime) + "<="+ MIN_SAFE_TIME);
    
                    if (currentTimeMillis - ipAccessTime <= MIN_SAFE_TIME) {
                        limitedIpMap.put(ip, currentTimeMillis + LIMITED_TIME_MILLIS);
                        request.setAttribute("remainingTime", LIMITED_TIME_MILLIS);
    
                        log.debug("ip访问过于频繁:LIMITED_TIME_MILLIS:"+LIMITED_TIME_MILLIS);
    
                        log.debug("ip访问过于频繁:"+ip);
                        throw new RuntimeException("ip访问过于频繁");
                    } else {
                        initIpVisitsNumber(ipMap, ip);
                    }
                }
            } else {
                initIpVisitsNumber(ipMap, ip);
                System.out.println("您首次访问该网站");
            }
            context.setAttribute("ipMap", ipMap);
            chain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        /**
         * @Description 过滤受限的IP,剔除已经到期的限制IP
         * @param limitedIpMap
         */
        private void filterLimitedIpMap(ConcurrentHashMap<String, Long> limitedIpMap) {
            if (limitedIpMap == null) {
                return;
            }
            Set<String> keys = limitedIpMap.keySet();
            Iterator<String> keyIt = keys.iterator();
            long currentTimeMillis = System.currentTimeMillis();
            while (keyIt.hasNext()) {
                long expireTimeMillis = limitedIpMap.get(keyIt.next());
                log.debug("expireTimeMillis <= currentTimeMillis:"+ expireTimeMillis+" <="+ currentTimeMillis);
                if (expireTimeMillis <= currentTimeMillis) {
                    keyIt.remove();
                }
            }
        }
    
        /**
         * @Description 是否是被限制的IP
         * @param limitedIpMap
         * @param ip
         * @return true : 被限制 | false : 正常
         */
        private boolean isLimitedIP(ConcurrentHashMap<String, Long> limitedIpMap, String ip) {
            if (limitedIpMap == null || ip == null) {
                // 没有被限制
                return false;
            }
            Set<String> keys = limitedIpMap.keySet();
            Iterator<String> keyIt = keys.iterator();
            while (keyIt.hasNext()) {
                String key = keyIt.next();
                if (key.equals(ip)) {
                    // 被限制的IP
                    return true;
                }
            }
            return false;
        }
    
        /**
         * 初始化用户访问次数和访问时间
         *
         * @param ipMap
         * @param ip
         */
        private void initIpVisitsNumber(ConcurrentHashMap<String, Long[]> ipMap, String ip) {
            Long[] ipInfo = new Long[2];
            ipInfo[0] = 0L;// 访问次数
            ipInfo[1] = System.currentTimeMillis();// 初次访问时间
            ipMap.put(ip, ipInfo);
        }
    
    
    
    }
    

      

    2. 创建一个监听器:需要初始化俩个容器:

    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    import java.util.concurrent.ConcurrentHashMap;
    
    
    @Slf4j
    @WebListener
    public class MyApplicationListener implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            log.debug("liting: contextInitialized");
            log.debug("MyApplicationListener初始化成功");
            ServletContext context = sce.getServletContext();
            // IP存储器
            ConcurrentHashMap<String, Long[]> ipMap = new ConcurrentHashMap<>();
            context.setAttribute("ipMap", ipMap);
            // 限制IP存储器:存储被限制的IP信息
            ConcurrentHashMap<String, Long> limitedIpMap = new ConcurrentHashMap<String, Long>();
            context.setAttribute("limitedIpMap", limitedIpMap);
            log.debug("ipmap:"+ipMap.toString()+";limitedIpMap:"+limitedIpMap.toString()+"初始化成功。。。。。");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            // TODO Auto-generated method stub
    
        }
    
    
    }
    

      

    3.iputil

    import javax.servlet.http.HttpServletRequest;
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    public class IPUtil {
    
        public static String getRemoteIpAddr(HttpServletRequest request) {
            String ip = request.getHeader("x-forwarded-for");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
                if("127.0.0.1".equals(ip)||"0:0:0:0:0:0:0:1".equals(ip)){
                    //根据网卡取本机配置的IP
                    InetAddress inet=null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ip= inet.getHostAddress();
                }
            }
            return ip;
        }
    
    
    }
    

      

    4配置

    springboot启动类中添加过滤器和监听器的包扫描

    @ServletComponentScan(basePackages="cn.xxx.common")
    

      

    spring web.xml

    过滤器

    <filter>
    		<filter-name>ipFilter</filter-name>
    		<filter-class>com.xxxx.common.filter.IpFilter</filter-class>
    	</filter>
    	<filter-mapping>
    		<filter-name>ipFilter</filter-name>
    		<url-pattern>/dyflight/**</url-pattern>
    	</filter-mapping>
    

      

    监听器:

    <listener>
    		<listener-class>com.xxxx.common.Listener.MyApplicationListener</listener-class>
    	</listener>
    

      

  • 相关阅读:
    算法训练 P1103
    算法训练 表达式计算
    算法训练 表达式计算
    基础练习 时间转换
    基础练习 字符串对比
    Codeforces 527D Clique Problem
    Codeforces 527C Glass Carving
    Codeforces 527B Error Correct System
    Codeforces 527A Glass Carving
    Topcoder SRM 655 DIV1 250 CountryGroupHard
  • 原文地址:https://www.cnblogs.com/achengmu/p/12681190.html
Copyright © 2011-2022 走看看