java 实现IP访问量控制

网站中发现有人恶意频繁的注册账号,打算在注册接口处增加效验工具,思路如下:

记录访问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);
		//
	}
	
}


不写测试用例的程序员不是好程序员;


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值