网站中发现有人恶意频繁的注册账号,打算在注册接口处增加效验工具,思路如下:
记录访问IP 和 时间
如果在五分钟内连续访问更新计时器更新计数器
10分钟内不访问计时器清零
思路很简单源码如下
package com.zcjy.mft.util;
import java.util.Date;
import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Forbidener {
final Log log = LogFactory
.getLog(Forbidener.class);
private Forbidener(){
ipmap = new LRUMap(100000);
}
public static Forbidener forbidener;
public static Forbidener getInstance(){
if(forbidener == null){
forbidener = new Forbidener();
}
return forbidener;
}
LRUMap ipmap = null ;
/**
* 超过次数封禁
*/
long maxTime = 10;
/**
* 超过访问时间重新计时
*/
long minInteval = 60*1000*60*4;
/**
* 封禁的时间
*/
long forbidenTime = 60*1000*60*4;
public int getMapSize() {
return ipmap.size();
}
public void setMaxTime(int i) {
maxTime = i;
}
public void setMinInteval(int i) {
minInteval = i;
}
public void setForbidenTime(int i) {
forbidenTime = i;
}
public void setMaxMapSize(int i) {
ipmap = new LRUMap(i);
}
public boolean check(String IP){
IPer iper = (IPer)ipmap.get(IP);
if(iper == null){
iper = new IPer();
iper.lastVisiterTime = new Date();
iper.visitTimes = 1;
ipmap.put(IP, iper);
return true;
}
Date now = new Date();
if(iper.isForbiden){
if(now.getTime() - iper.lastVisiterTime.getTime() > forbidenTime){
//解封
iper.isForbiden = false;
iper.visitTimes = 1;
iper.lastVisiterTime = now;
log.debug("unforbiden ip:" + IP);
return true;
}else{
return false;
}
}
if(now.getTime() - iper.lastVisiterTime.getTime() > minInteval){
//太久没有访问了,重新计时
iper.lastVisiterTime = now;
iper.visitTimes = 1;
iper.isForbiden = false;
log.debug("reset ip:" + IP);
return true;
}else{
iper.lastVisiterTime = now;
iper.visitTimes = iper.visitTimes +1;
if(iper.visitTimes > maxTime){
//封禁
iper.isForbiden = true;
log.debug("forbiden ip:" + IP);
return false;
}else{
return true;
}
}
}
public static void main(String[] args) throws InterruptedException {
Date d1 = new Date();
Thread.sleep(1000);
Date d2 = new Date();
System.out.println(d1.getTime() - d2.getTime());
}
}
class IPer {
Date lastVisiterTime ;
int visitTimes;
boolean isForbiden = false;
}
测试代码如下
package com.zcjy.mft.util;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
import com.zcjy.mft.util.Forbidener;
public class TestForbidener {
public static void setup(){
//构造初始化数据
}
@AfterClass
public static void clear(){
}
/**
* @throws InterruptedException
*/
@Test
public void check() throws InterruptedException{
//测试十次封禁
Forbidener fb = Forbidener.getInstance();
fb.setMaxTime(10);
fb.setMinInteval(10*1000);
fb.setForbidenTime(60*1000);
fb.setMaxMapSize(3);
String testIP = "127.0.0.1";
for(int i = 1 ; i <= 10;i++){
System.out.println("check");
Assert.assertTrue(fb.check(testIP));
Thread.sleep(1000);
}
Assert.assertFalse(fb.check(testIP));
//测试解封
System.out.println("sleep more than 1 min");
Thread.sleep(65*1000);
Assert.assertTrue(fb.check(testIP));
//测试最短周期
for(int i = 1;i<= 9 ;i++){
Assert.assertTrue(fb.check(testIP));
System.out.println("check");
Thread.sleep(1000);
}
System.out.println("sleep more than 10 sec");
Thread.sleep(15*1000);
Assert.assertTrue(fb.check(testIP));
//测试淘汰
fb.check("1");
fb.check("2");
Assert.assertTrue(fb.getMapSize() == 3);
fb.check("3");
Assert.assertTrue(fb.getMapSize() == 3);
//
}
}