日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java限制ip登陆次数_手把手教你自定义IP访问次数限制器

發(fā)布時(shí)間:2023/12/18 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java限制ip登陆次数_手把手教你自定义IP访问次数限制器 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

修訂版已經(jīng)發(fā)布:請(qǐng)看完這篇文章后再去看修訂版

前段時(shí)間弄爬蟲的時(shí)候,在爬iteye的時(shí)候碰到過一個(gè)場(chǎng)景,Spider跑幾次或者抓取的時(shí)間間隔小一點(diǎn)之后就會(huì)出現(xiàn)401錯(cuò)誤

16-08-16 15:05:49,687 INFO us.codecraft.webmagic.Spider(Spider.java:307) ## Spider 843977358.iteye.com started!

16-08-16 15:05:49,696 INFO us.codecraft.webmagic.downloader.HttpClientDownloader(HttpClientDownloader.java:87) ## downloading page http://843977358.iteye.com/

16-08-16 15:05:50,056 WARN us.codecraft.webmagic.downloader.HttpClientDownloader(HttpClientDownloader.java:100) ## code error 401 http://843977358.iteye.com/

不用想,一定是人家后臺(tái)給限制住了。

因此,自己就瞎鼓搗搞了一個(gè)簡(jiǎn)單點(diǎn)的,僅僅可以實(shí)現(xiàn)對(duì)用戶IP次數(shù)的檢查和對(duì)違規(guī)用戶的封禁

用到的技術(shù)

過濾器(Filter):統(tǒng)計(jì)用戶訪問次數(shù),記錄訪問時(shí)間、封禁時(shí)間

監(jiān)聽器(Listener):工程運(yùn)行時(shí)初始化IP存儲(chǔ)器(此處用的Map)

我的思路:

工程啟動(dòng)時(shí),創(chuàng)建兩個(gè)Map,一個(gè)(ipMap)用來存放用戶Ip和訪問時(shí)間等主要信息,另一個(gè)(limitedIpMap)用來存放被限制的用戶IP。Map的key為用戶的IP,value為具體內(nèi)容。

當(dāng)用戶訪問系統(tǒng)時(shí),通過IPFilter檢查limitedIpMap中是否存在當(dāng)前IP,如果存在說明該IP之前存在過惡意刷新訪問,已經(jīng)被限制,跳轉(zhuǎn)到異常提示頁(yè)面;如果limitedIpMap

中不存在則檢查ipMap中是否存在當(dāng)前IP,如果ipMap中不存在則說明用戶初次訪問,用戶訪問次數(shù)+1,初始訪問時(shí)間為當(dāng)前時(shí)間;如果存在則檢查用戶訪問次數(shù)是否在規(guī)定的短時(shí)間內(nèi)進(jìn)行了大量的訪問操作;如果是,則將當(dāng)前IP添加到limitedIpMap中,并跳轉(zhuǎn)到異常提示頁(yè)面,否則不進(jìn)行操作,直接放行本次請(qǐng)求。

(簡(jiǎn)單畫了下流程圖,看不懂的就腦補(bǔ)吧,腦補(bǔ)吧,補(bǔ)吧,吧...)

配置文件:

IPFilter

com.test.interceptor.IPFilter

IPFilter

/render/*

com.test.listener.MyListener

監(jiān)聽器MyListener:

import java.util.HashMap;

import java.util.Map;

import javax.servlet.ServletContext;

import javax.servlet.ServletContextEvent;

import javax.servlet.ServletContextListener;

/**

* @Description 自定義監(jiān)聽器,項(xiàng)目啟動(dòng)時(shí)初始化兩個(gè)全局的map,

* ipMap(ip存儲(chǔ)器,記錄IP的訪問次數(shù)、訪問時(shí)間)

* limitedIpMap(限制IP存儲(chǔ)器)用來存儲(chǔ)每個(gè)訪問用戶的IP以及訪問的次數(shù)

* @author zhangyd

* @date 2016年7月28日 下午5:47:23

* @since JDK : 1.7

*/

public class MyListener implements ServletContextListener {

@Override

public void contextInitialized(ServletContextEvent sce) {

ServletContext context = sce.getServletContext();

// IP存儲(chǔ)器

Map ipMap = new HashMap();

context.setAttribute("ipMap", ipMap);

// 限制IP存儲(chǔ)器:存儲(chǔ)被限制的IP信息

Map limitedIpMap = new HashMap();

context.setAttribute("limitedIpMap", limitedIpMap);

}

@Override

public void contextDestroyed(ServletContextEvent sce) {

}

}

過濾器IPFilter:

import java.io.IOException;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.test.util.IPUtil;

/**

*

* @Description 自定義過濾器,用來判斷IP訪問次數(shù)是否超限。

* 如果前臺(tái)用戶訪問網(wǎng)站的頻率過快(比如:達(dá)到或超過50次/s),則判定該IP為惡意刷新操作,限制該ip訪問

* 默認(rèn)限制訪問時(shí)間為1小時(shí),一小時(shí)后自定解除限制

*

* @author zhangyd

* @date 2016年7月28日 下午5:54:51

* @since JDK : 1.7

*/

public class IPFilter implements Filter {

/**

* 默認(rèn)限制時(shí)間(單位:ms)

*/

private static final long LIMITED_TIME_MILLIS = 60 * 60 * 1000;

/**

* 用戶連續(xù)訪問最高閥值,超過該值則認(rèn)定為惡意操作的IP,進(jìn)行限制

*/

private static final int LIMIT_NUMBER = 20;

/**

* 用戶訪問最小安全時(shí)間,在該時(shí)間內(nèi)如果訪問次數(shù)大于閥值,則記錄為惡意IP,否則視為正常訪問

*/

private static final int MIN_SAFE_TIME = 5000;

private FilterConfig config;

@Override

public void init(FilterConfig filterConfig) throws ServletException {

this.config = filterConfig;

}

/**

* @Description 核心處理代碼

* @param servletRequest

* @param servletResponse

* @param chain

* @throws IOException

* @throws ServletException

* @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存儲(chǔ)器:存儲(chǔ)被限制的IP信息

Map limitedIpMap = (Map) context.getAttribute("limitedIpMap");

// 過濾受限的IP

filterLimitedIpMap(limitedIpMap);

// 獲取用戶IP

String ip = IPUtil.getIp(request);

// 判斷是否是被限制的IP,如果是則跳到異常頁(yè)面

if (isLimitedIP(limitedIpMap, ip)) {

long limitedTime = limitedIpMap.get(ip) - System.currentTimeMillis();

// 剩余限制時(shí)間(用為從毫秒到秒轉(zhuǎn)化的一定會(huì)存在些許誤差,但基本可以忽略不計(jì))

request.setAttribute("remainingTime", ((limitedTime / 1000) + (limitedTime % 1000 > 0 ? 1 : 0)));

request.getRequestDispatcher("/error/overLimitIP").forward(request, response);

return;

}

// 獲取IP存儲(chǔ)器

Map ipMap = (Map) context.getAttribute("ipMap");

// 判斷存儲(chǔ)器中是否存在當(dāng)前IP,如果沒有則為初次訪問,初始化該ip

// 如果存在當(dāng)前ip,則驗(yàn)證當(dāng)前ip的訪問次數(shù)

// 如果大于限制閥值,判斷達(dá)到閥值的時(shí)間,如果不大于[用戶訪問最小安全時(shí)間]則視為惡意訪問,跳轉(zhuǎn)到異常頁(yè)面

if (ipMap.containsKey(ip)) {

Long[] ipInfo = ipMap.get(ip);

ipInfo[0] = ipInfo[0] + 1;

System.out.println("當(dāng)前第[" + (ipInfo[0]) + "]次訪問");

if (ipInfo[0] > LIMIT_NUMBER) {

Long ipAccessTime = ipInfo[1];

Long currentTimeMillis = System.currentTimeMillis();

if (currentTimeMillis - ipAccessTime <= MIN_SAFE_TIME) {

limitedIpMap.put(ip, currentTimeMillis + LIMITED_TIME_MILLIS);

request.setAttribute("remainingTime", LIMITED_TIME_MILLIS);

request.getRequestDispatcher("/error/overLimitIP").forward(request, response);

return;

} else {

initIpVisitsNumber(ipMap, ip);

}

}

} else {

initIpVisitsNumber(ipMap, ip);

System.out.println("您首次訪問該網(wǎng)站");

}

context.setAttribute("ipMap", ipMap);

chain.doFilter(request, response);

}

@Override

public void destroy() {

}

/**

* @Description 是否是被限制的IP

* @author zhangyd

* @date 2016年8月8日 下午5:39:17

* @param limitedIpMap

* @param ip

* @return true : 被限制 false : 正常

*/

private boolean isLimitedIP(Map limitedIpMap, String ip) {

if (limitedIpMap == null ip == null) {

// 沒有被限制

return false;

}

Set keys = limitedIpMap.keySet();

Iterator keyIt = keys.iterator();

while (keyIt.hasNext()) {

String key = keyIt.next();

if (key.equals(ip)) {

// 被限制的IP

return true;

}

}

return false;

}

/**

* @Description 過濾受限的IP,剔除已經(jīng)到期的限制IP

* @author zhangyd

* @date 2016年8月8日 下午5:34:33

* @param limitedIpMap

*/

private void filterLimitedIpMap(Map limitedIpMap) {

if (limitedIpMap == null) {

return;

}

Set keys = limitedIpMap.keySet();

Iterator keyIt = keys.iterator();

long currentTimeMillis = System.currentTimeMillis();

while (keyIt.hasNext()) {

long expireTimeMillis = limitedIpMap.get(keyIt.next());

if (expireTimeMillis <= currentTimeMillis) {

keyIt.remove();

}

}

}

/**

* 初始化用戶訪問次數(shù)和訪問時(shí)間

*

* @author zhangyd

* @date 2016年7月29日 上午10:01:39

* @param ipMap

* @param ip

*/

private void initIpVisitsNumber(Map ipMap, String ip) {

Long[] ipInfo = new Long[2];

ipInfo[0] = 0L;// 訪問次數(shù)

ipInfo[1] = System.currentTimeMillis();// 初次訪問時(shí)間

ipMap.put(ip, ipInfo);

}

}

為了方便測(cè)試,我把封禁時(shí)間調(diào)到1分鐘

/**

* 默認(rèn)限制時(shí)間(單位:ms)

*/

private static final long LIMITED_TIME_MILLIS = 60 * 1000;

/**

* 用戶連續(xù)訪問最高閥值,超過該值則認(rèn)定為惡意操作的IP,進(jìn)行限制

*/

private static final int LIMIT_NUMBER = 20;

/**

* 用戶訪問最小安全時(shí)間,在該時(shí)間內(nèi)如果訪問次數(shù)大于閥值,則記錄為惡意IP,否則視為正常訪問

*/

private static final int MIN_SAFE_TIME = 5000;

上面這三項(xiàng)是自定義的,根據(jù)自己情況來。

測(cè)試:

演示統(tǒng)共分三步:

第一步:正常訪問并且間隔時(shí)間略長(zhǎng),訪問20次為第一步

第二步:按住F5狂刷,一直到跳轉(zhuǎn)到限制頁(yè)面為第二步

第三步:等待1min,限制時(shí)間過后,重新刷新頁(yè)面

(此處沒有大象......)

正經(jīng)的!看測(cè)試效果圖:

我有罪,我不該把時(shí)間調(diào)成1min的, 應(yīng)該20秒。。。好吧。

大功告成!!! Happy!!

原文鏈接:原文也是我寫的,謝謝。咔咔!

修訂版已經(jīng)發(fā)布:請(qǐng)看完這篇文章后再去看修訂版

我可以對(duì)一個(gè)人無限的好,前提是值得。 ——慕冬雪

總結(jié)

以上是生活随笔為你收集整理的java限制ip登陆次数_手把手教你自定义IP访问次数限制器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。