失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Springboot过滤器禁止ip频繁访问功能实现

Springboot过滤器禁止ip频繁访问功能实现

时间:2023-05-16 16:13:25

相关推荐

Springboot过滤器禁止ip频繁访问功能实现

在开发 Web 项目的时候,经常需要过滤器来处理一些请求,包括字符集转换什么的,记录请求日志什么的等等。在之前的 Web 开发中,我们习惯把过滤器配置到 web.xml 中,但是在 SpringBoot 中,兵没有这个配置文件,该如何操作呢?

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;@Overridepublic 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")@Overridepublic 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");// 过滤受限的IPfilterLimitedIpMap(limitedIpMap);// 获取用户IPString 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);}@Overridepublic 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)) {// 被限制的IPreturn 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@WebListenerpublic class MyApplicationListener implements ServletContextListener {@Overridepublic 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()+"初始化成功。。。。。");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {// TODO Auto-generated method stub}}

3.iputil

import javax.servlet.http.HttpServletRequest;import .InetAddress;import .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)){//根据网卡取本机配置的IPInetAddress inet=null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ip= inet.getHostAddress();}}return ip;}}

4.配置

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

@ServletComponentScan(basePackages=“mon”)

spring web.xml

过滤器

<filter><filter-name>ipFilter</filter-name><filter-class>mon.filter.IpFilter</filter-class></filter><filter-mapping><filter-name>ipFilter</filter-name><url-pattern>/dyflight/**</url-pattern></filter-mapping>

监听器

<listener><listener-class>mon.Listener.MyApplicationListener</listener-class></listener>

总结

篇幅有限!篇幅有限!关于Springboot过滤器禁止ip频繁访问功能实现,就聊到这儿啦…啦…啦…

以上小编所介绍的全部相关的笔记资料都已整理成册,不论是Redis面试+Redis实战pdf,还是MongDB快速上手+MongDB集群安全等手写pdf笔记,想白嫖都很so easy!!

——如果你get到了,那就点个赞转发支持一波吧!

——整理不易,白嫖私信我领取源码学习资料,100%回复分享!

——也可以添加小助手vx:xcw18874131605 获取源码资料哦

——祝前程似锦,offer不断,好好学习,天天向上!

如果觉得《Springboot过滤器禁止ip频繁访问功能实现》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。