Springboot过滤器禁止ip频繁访问功能实现
在开发Web项目的时候,经常需要过滤器来处理一些请求,包括字符集转换什么的,记录请求日志什么的等等。在之前的Web开发中,我们习惯把过滤器配置到web.xml中,但是在SpringBoot中,兵没有这个配置文件,该如何操作呢?
1.编写一个过滤器:
importlombok.extern.slf4j.Slf4j; importjavax.servlet.*; importjavax.servlet.annotation.WebFilter; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.io.IOException; importjava.util.Iterator; importjava.util.Set; importjava.util.concurrent.ConcurrentHashMap; @Slf4j @WebFilter(urlPatterns="/dyflight/*") publicclassIpFilterimplementsFilter{ /** *默认限制时间(单位:ms)3600000,3600(s), */ privatestaticfinallongLIMITED_TIME_MILLIS=10*1000; /** *用户连续访问最高阀值,超过该值则认定为恶意操作的IP,进行限制 */ privatestaticfinalintLIMIT_NUMBER=5; /** *用户访问最小安全时间,在该时间内如果访问次数大于阀值,则记录为恶意IP,否则视为正常访问 */ privatestaticfinalintMIN_SAFE_TIME=5000; privateFilterConfigconfig; @Override publicvoidinit(FilterConfigfilterConfig)throwsServletException{ this.config=filterConfig;//设置属性filterConfig } /*(non-Javadoc) *@seejavax.servlet.Filter#doFilter(javax.servlet.ServletRequest,javax.servlet.ServletResponse,javax.servlet.FilterChain) */ @SuppressWarnings("unchecked") @Override publicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainchain) throwsIOException,ServletException{ HttpServletRequestrequest=(HttpServletRequest)servletRequest; HttpServletResponseresponse=(HttpServletResponse)servletResponse; ServletContextcontext=config.getServletContext(); //获取限制IP存储器:存储被限制的IP信息 //MaplimitedIpMap=(Map )context.getAttribute("limitedIpMap"); ConcurrentHashMap limitedIpMap=(ConcurrentHashMap )context.getAttribute("limitedIpMap"); //过滤受限的IP filterLimitedIpMap(limitedIpMap); //获取用户IP Stringip=IPUtil.getRemoteIpAddr(request); System.err.println("ip:"+ip); //判断是否是被限制的IP,如果是则跳到异常页面 if(isLimitedIP(limitedIpMap,ip)){ longlimitedTime=limitedIpMap.get(ip)-System.currentTimeMillis(); //剩余限制时间(用为从毫秒到秒转化的一定会存在些许误差,但基本可以忽略不计) request.setAttribute("remainingTime",((limitedTime/1000)+(limitedTime%1000>0?1:0))); System.err.println("ip访问过于频繁:"+ip); thrownewRuntimeException("ip访问过于频繁"); } //获取IP存储器 ConcurrentHashMap ipMap=(ConcurrentHashMap )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){ LongipAccessTime=ipInfo[1]; LongcurrentTimeMillis=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); thrownewRuntimeException("ip访问过于频繁"); }else{ initIpVisitsNumber(ipMap,ip); } } }else{ initIpVisitsNumber(ipMap,ip); System.out.println("您首次访问该网站"); } context.setAttribute("ipMap",ipMap); chain.doFilter(request,response); } @Override publicvoiddestroy(){ //TODOAuto-generatedmethodstub } /** *@Description过滤受限的IP,剔除已经到期的限制IP *@paramlimitedIpMap */ privatevoidfilterLimitedIpMap(ConcurrentHashMap limitedIpMap){ if(limitedIpMap==null){ return; } Set keys=limitedIpMap.keySet(); Iterator keyIt=keys.iterator(); longcurrentTimeMillis=System.currentTimeMillis(); while(keyIt.hasNext()){ longexpireTimeMillis=limitedIpMap.get(keyIt.next()); log.debug("expireTimeMillis<=currentTimeMillis:"+expireTimeMillis+"<="+currentTimeMillis); if(expireTimeMillis<=currentTimeMillis){ keyIt.remove(); } } } /** *@Description是否是被限制的IP *@paramlimitedIpMap *@paramip *@returntrue:被限制|false:正常 */ privatebooleanisLimitedIP(ConcurrentHashMap limitedIpMap,Stringip){ if(limitedIpMap==null||ip==null){ //没有被限制 returnfalse; } Set keys=limitedIpMap.keySet(); Iterator keyIt=keys.iterator(); while(keyIt.hasNext()){ Stringkey=keyIt.next(); if(key.equals(ip)){ //被限制的IP returntrue; } } returnfalse; } /** *初始化用户访问次数和访问时间 * *@paramipMap *@paramip */ privatevoidinitIpVisitsNumber(ConcurrentHashMap ipMap,Stringip){ Long[]ipInfo=newLong[2]; ipInfo[0]=0L;//访问次数 ipInfo[1]=System.currentTimeMillis();//初次访问时间 ipMap.put(ip,ipInfo); } }
2.创建一个监听器:需要初始化俩个容器:
importlombok.extern.slf4j.Slf4j; importjavax.servlet.ServletContext; importjavax.servlet.ServletContextEvent; importjavax.servlet.ServletContextListener; importjavax.servlet.annotation.WebListener; importjava.util.concurrent.ConcurrentHashMap; @Slf4j @WebListener publicclassMyApplicationListenerimplementsServletContextListener{ @Override publicvoidcontextInitialized(ServletContextEventsce){ log.debug("liting:contextInitialized"); log.debug("MyApplicationListener初始化成功"); ServletContextcontext=sce.getServletContext(); //IP存储器 ConcurrentHashMapipMap=newConcurrentHashMap<>(); context.setAttribute("ipMap",ipMap); //限制IP存储器:存储被限制的IP信息 ConcurrentHashMap limitedIpMap=newConcurrentHashMap (); context.setAttribute("limitedIpMap",limitedIpMap); log.debug("ipmap:"+ipMap.toString()+";limitedIpMap:"+limitedIpMap.toString()+"初始化成功。。。。。"); } @Override publicvoidcontextDestroyed(ServletContextEventsce){ //TODOAuto-generatedmethodstub } }
3.iputil
importjavax.servlet.http.HttpServletRequest; importjava.net.InetAddress; importjava.net.UnknownHostException; publicclassIPUtil{ publicstaticStringgetRemoteIpAddr(HttpServletRequestrequest){ Stringip=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 InetAddressinet=null; try{ inet=InetAddress.getLocalHost(); }catch(UnknownHostExceptione){ e.printStackTrace(); } ip=inet.getHostAddress(); } } returnip; } }
4配置
springboot启动类中添加过滤器和监听器的包扫描
@ServletComponentScan(basePackages="cn.xxx.common")
springweb.xml
过滤器
ipFilter com.xxxx.common.filter.IpFilter ipFilter /dyflight/**
监听器:
com.xxxx.common.Listener.MyApplicationListener
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。