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");
ConcurrentHashMaplimitedIpMap=(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存储器
ConcurrentHashMapipMap=(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(ConcurrentHashMaplimitedIpMap){
if(limitedIpMap==null){
return;
}
Setkeys=limitedIpMap.keySet();
IteratorkeyIt=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(ConcurrentHashMaplimitedIpMap,Stringip){
if(limitedIpMap==null||ip==null){
//没有被限制
returnfalse;
}
Setkeys=limitedIpMap.keySet();
IteratorkeyIt=keys.iterator();
while(keyIt.hasNext()){
Stringkey=keyIt.next();
if(key.equals(ip)){
//被限制的IP
returntrue;
}
}
returnfalse;
}
/**
*初始化用户访问次数和访问时间
*
*@paramipMap
*@paramip
*/
privatevoidinitIpVisitsNumber(ConcurrentHashMapipMap,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信息
ConcurrentHashMaplimitedIpMap=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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。