1.Filter
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
if (loginStatusCache.getDefendStatus().equals("Y")) {
// loginStatusCache = LoginStatusCache.getInstance(limitVisitTime,
// measurementTimeInSeconds, blockDurationTimeInSeconds);
String customerIP = HostAddressUtils.getRealIPAddresses((HttpServletRequest) request);
Map<String, String> newUserInfo = null;
Map<String, String> userInfo = null;
if (loginStatusCache.get(customerIP) == null) {
try {
// lock.writeLock().lock();
lock.lock();
// 建立新使用者info.
newUserInfo = createNewUserInfo(customerIP);
userInfo = (Map<String, String>) loginStatusCache.putIfAbsent(customerIP, newUserInfo);
} finally {
lock.unlock();
}
// 此行不需加入鎖定
checkIfBlock(userInfo == null ? newUserInfo.get("blockStatus") : userInfo.get("blockStatus"), request,
response, chain, customerIP);
} else {
String blockStatus = null;
try {
lock.lock();
blockStatus = loginStatusCache.addVisitTimes(customerIP);
} finally {
lock.unlock();
}
checkIfBlock(blockStatus, request, response, chain, customerIP);
}
} else {
chain.doFilter(request, response);
}
}
/***
* 建立連入使用者資訊,包括登入時間、瀏覽次數、是否被鎖定等資訊
*
* @return Map<String, String> userInfo
*/
private Map<String, String> createNewUserInfo(String ip) {
// 塞入userInfo的資訊(loginTime, visitTimes, blockStatus)
Map<String, String> userInfo = new HashMap<String, String>();
userInfo.put("ip", ip);
userInfo.put("loginTime", String.valueOf(System.currentTimeMillis()));
userInfo.put("visitTimes", "1");
userInfo.put("blockStatus", "false");
return userInfo;
}
/***
* 依據blockStatus決定是否回應正常的頁面 "false":正常流程; "true":回應limit字串
*
* @param blockStatus
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
*/
private void checkIfBlock(String blockStatus, ServletRequest request, ServletResponse response, FilterChain chain, String ip)
throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
if (blockStatus.equalsIgnoreCase("true")) {
PrintWriter pw = response.getWriter();
//pw.println(String.format(new String("此IP[%s]已被锁定".getBytes("UTF-8"),"UTF-8") , ip));
pw.println(String.format("此IP[%s]已被锁定" , ip));
pw.flush();
pw.close();
} else
chain.doFilter(request, response);
}
2.LoginStatus
public class LoginStatusCache {
private static Logger log = LogUtils.pay;
private ReadWriteLock lock = new ReentrantReadWriteLock();
private static volatile LoginStatusCache instance = null;
private volatile Map<String, Map<String, String>> cacheMap = null; // key:登入的IP,
// value:
// Map:一分鐘內瀏覽次數,是否block狀態,第一次進入頁面時間
private String defendStatus = "N";
private int limitVisitTime = 0;
private int measurementTimeInSeconds = 0;
private int blockDurationTimeInSeconds = 0;
private int reloadDefendParamsTimeInSeconds = 0;
private String nextReloadTime = null;
private LoginStatusCache(int limitVisitTime, int measurementTimeInSeconds, int blockDurationTimeInSeconds,
String defendStatus, int reloadDefendParamsTimeInSeconds) {
this.defendStatus = defendStatus;
this.limitVisitTime = limitVisitTime;
this.measurementTimeInSeconds = measurementTimeInSeconds;
this.blockDurationTimeInSeconds = blockDurationTimeInSeconds;
this.reloadDefendParamsTimeInSeconds = reloadDefendParamsTimeInSeconds;
log.debug("[LOG]defendStatus:" + defendStatus);
log.debug("[LOG]limitVisitTime:" + limitVisitTime + " 次");
log.debug("[LOG]measurementTimeInSeconds:" + measurementTimeInSeconds + " 秒");
log.debug("[LOG]blockDurationTimeInSeconds:" + blockDurationTimeInSeconds + " 秒");
log.debug("[LOG]reloadDefendParamsTimeInSeconds:" + reloadDefendParamsTimeInSeconds + " 秒");
cacheMap = new ConcurrentHashMap<String, Map<String, String>>();
Thread cleanerJob = new Thread(new UserInfoMapCleaner());
cleanerJob.setDaemon(true);
cleanerJob.start();
}
public static LoginStatusCache getInstance(int limitVisitTime, int measurementTimeInSeconds,
int blockDurationTimeInSeconds, String defendStatus, int reloadDefendParamsTimeInSeconds) {
if (instance == null) {
synchronized (LoginStatusCache.class) {
if (instance == null) {
instance = new LoginStatusCache(limitVisitTime, measurementTimeInSeconds,
blockDurationTimeInSeconds, defendStatus, reloadDefendParamsTimeInSeconds);
}
}
}
return instance;
}
public static LoginStatusCache getInstance() {
return instance;
}
/***
* 若指定的key沒有指定的value(userInfo Map),就將userInfo存入cacheMap中(ip當成key)
* 並且回傳null,若存在則取出指定key對應的userInfo並將visitTimes累加1
*/
public Object putIfAbsent(String ip, Map<String, String> newUserInfo) {
@SuppressWarnings("unchecked")
Map<String, String> userInfo = (Map<String, String>) cacheMap.putIfAbsent(ip, newUserInfo);
if (userInfo != null) {
this.addVisitTimes(ip);
}
return userInfo;
}
/***
* 對傳入的ip將其一分鐘內的瀏覽次數(visitTimes)+1,若超過一分鐘內的瀏覽限制次數, 則將
* blockStatus設成"true",並且填入開始block的時間(startBlockTime)
*/
public String addVisitTimes(String ip) {
Map<String, String> userInfo = (Map<String, String>) cacheMap.get(ip);
if (userInfo != null) {
if (userInfo.get("blockStatus").equalsIgnoreCase("true"))
return userInfo.get("blockStatus");
int visitTimes = Integer.parseInt(userInfo.get("visitTimes")) + 1;
userInfo.put("visitTimes", String.valueOf(visitTimes));
if (visitTimes > this.limitVisitTime) {
userInfo.put("blockStatus", "true");
userInfo.put("startBlockTime", String.valueOf(System.currentTimeMillis()));
}
}
return userInfo.get("blockStatus");
}
public Map<String, String> get(String key) {
return cacheMap.get(key);
}
public void put(String key, Map<String, String> value) {
cacheMap.put(key, value);
}
public Map<String, String> getAndRemove(String key) {
return cacheMap.remove(key);
}
public Map<String, Map<String, String>> getUserLoginCacheMap() {
return cacheMap;
}
public String getDefendStatus() {
try{
lock.readLock().lock();
return defendStatus;
}finally{
lock.readLock().unlock();
}
}
public int getLimitVisitTime() {
return limitVisitTime;
}
public int getMeasurementTimeInSeconds() {
return measurementTimeInSeconds;
}
public int getBlockDurationTimeInSeconds() {
return blockDurationTimeInSeconds;
}
public String getNextReloadTime() {
try{
lock.readLock().lock();
return nextReloadTime;
}finally{
lock.readLock().unlock();
}
}
public int getReloadDefendParamsTimeInSeconds() {
return reloadDefendParamsTimeInSeconds;
}
public void setReloadDefendParamsTimeInSeconds(int reloadDefendParamsTimeInSeconds) {
this.reloadDefendParamsTimeInSeconds = reloadDefendParamsTimeInSeconds;
}
class UserInfoMapCleaner implements Runnable {
// private boolean isCheck = true;
long checkDurationInMillis = (measurementTimeInSeconds) * 1000; // 設定job多久去檢查一次cacheMap(設定60秒,基本上至少要大於等於measurementTimeInSeconds)
long lastLoadingParamsTime = System.currentTimeMillis(); // 進來前剛載入過參數,所以假設最近一次重載時間是現在
long nextLoadingParamsTime = lastLoadingParamsTime + reloadDefendParamsTimeInSeconds * 1000;
private final String DEFENSE_ENABLED = "N";
private final int DEFAULT_DEFENSE_MAX_ACCESS_TIMES = 60; //
private final int DEFAULT_MEASUREMENT_TIME_IN_SECONDS = 60; //
private final int DEFAULT_BLOCK_DURATION_TIME_IN_SECONDS = 1 * 60; //
@Override
public void run() {
// TODO Auto-generated method stub
FunctionExecuteTimer timer = new FunctionExecuteTimer();
while (true) {
//檢查是否該重新載入防禦參數(每10分鐘重載一次)
checkIfReloadDefendParams();
try {
Thread.sleep(checkDurationInMillis);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (defendStatus.equals("Y")){
FunctionExecuteTimer.setLogMessage("清除cacheMap花費時間:");
log.debug("==============開始清除防禦快取 cacheMap==============");
timer.start();
Collection<Map<String, String>> tempUsers = cacheMap.values();
log.debug("開始清除前,cacheMap Size:" + cacheMap.size());
long now = System.currentTimeMillis();
tempUsers.forEach(obj -> {
Map<String, String> userInfo = (Map<String, String>) obj;
String ip = userInfo.get("ip");
int visitTimes = Integer.parseInt(userInfo.get("visitTimes"));
long loginTime = Long.parseLong(userInfo.get("loginTime"));
long duration;
if (userInfo.get("blockStatus").equalsIgnoreCase("false")) {
// duration:從使用者第一次登入後至目前為止,瀏覽次數不能超過limitVisitTimeInOneMinute,duration即為登入期間
// 檢查是否有超過量測時間,visitTimes還沒超過限制次數的,將其從cacheMap移除
if ((duration = DateUtil.secondsBetween(loginTime, now)) > measurementTimeInSeconds) {
if (visitTimes <= limitVisitTime) {
log.debug(String.format("%s 已經登入%s次(%s秒)還未超過瀏覽次數限制[%s]", ip, visitTimes, duration,
limitVisitTime));
tempUsers.remove(obj);
log.debug(String.format("從cacheMap移除IP:%s的UserInfo,cacheMap Size:%s", ip,
cacheMap.size()));
} else {
// 登入時間超過時間限制,且瀏覽次數也超過限制
// 在addVisitTimes裡面就會判斷是否超過limitVisitTimeInOneMinute,超過就將blockStatus改成true
}
} else { // do nothing.
// 在addVisitTimes裡面就會判斷是否超過limitVisitTimeInOneMinute,超過就將blockStatus改成true
}
} else {
// 檢查block時間到的使用者,將其從cacheMap中移除
long startBlockTime = Long.parseLong(userInfo.get("startBlockTime"));
long actualBlockTime = DateUtil.secondsBetween(startBlockTime, now);
if (actualBlockTime >= blockDurationTimeInSeconds) {
tempUsers.remove(obj);
log.debug(String.format("%s已經被block %s分鐘,從cacheMap移除IP:%s的UserInfo,cacheMap Size:%s",
ip, actualBlockTime / 60, ip, cacheMap.size()));
}
}
});
log.debug(String.format("==============結束清除防禦快取 cacheMap,cacheMap Size:%s ==============", cacheMap.size()));
timer.stop();
}else{
cacheMap.clear();
log.info(String.format("防禦關閉,清除所有用戶連線記錄,cacheMap Size:%s", cacheMap.size()));
}
}
}
/***
* 檢查是否該重新載入防禦參數(每隔10分鐘重新載入一次)
*/
private void checkIfReloadDefendParams() {
Date now = new Date();
String nowTime = DateUtil.formatDate(now, "yyyy-MM-dd HH:mm:ss");
if (nextReloadTime == null){
try{
lock.writeLock().lock();
nextReloadTime = DateUtil.formatDate(new Date(nextLoadingParamsTime), "yyyy-MM-dd HH:mm:ss");
}finally{
lock.writeLock().unlock();
}
}
log.info(String.format("目前檢查時間:%s, 預估於%s 重新載入防禦參數", nowTime, nextReloadTime));
if (now.getTime() >= nextLoadingParamsTime) {
try{
lock.writeLock().lock();
String thisReloadTime = DateUtil.formatDate(new Date(nextLoadingParamsTime), "yyyy-MM-dd HH:mm:ss");
lastLoadingParamsTime = nextLoadingParamsTime;
nextLoadingParamsTime = lastLoadingParamsTime + reloadDefendParamsTimeInSeconds*1000;
nextReloadTime = DateUtil.formatDate(new Date(nextLoadingParamsTime), "yyyy-MM-dd HH:mm:ss");
//log.info("目前時間:"+ nowTime);
log.info(String.format("開始重新載入防禦參數, 下一次重新載入時間%s", thisReloadTime, nextReloadTime));
Map<String, String> defendParams = OrderPageBO.getDefendsParam();
defendStatus = StringUtils.isEmpty(defendParams.get("DEFENSE_ENABLED")) ? DEFENSE_ENABLED
: defendParams.get("DEFENSE_ENABLED");
log.info("重新載入防禦參數:"+ defendParams);
try {
limitVisitTime = Integer.parseInt(defendParams.get("DEFENSE_MAX_ACCESS_TIMES"));
} catch (NumberFormatException e) {
limitVisitTime = DEFAULT_DEFENSE_MAX_ACCESS_TIMES;
}
try {
measurementTimeInSeconds = Integer.parseInt(defendParams.get("DEFENSE_MEASURE_TIME")) * 60; // 單位是分鐘
} catch (NumberFormatException e) {
measurementTimeInSeconds = DEFAULT_MEASUREMENT_TIME_IN_SECONDS;
}
try {
blockDurationTimeInSeconds = Integer.parseInt(defendParams.get("DEFENSE_BLOCK_TIME")) * 60; // 單位是分鐘
} catch (NumberFormatException e) {
blockDurationTimeInSeconds = DEFAULT_BLOCK_DURATION_TIME_IN_SECONDS;
}
//lastLoadingParamsTime = nextLoadingParamsTime;
}finally{
lock.writeLock().unlock();
}
}/*else{
if (nextReloadTime == null){
try{
lock.writeLock().lock();
nextReloadTime = DateUtil.formatDate(new Date(nextLoadingParamsTime), "yyyy-MM-dd HH:mm:ss");
}finally{
lock.writeLock().unlock();
}
}
}*/
}
}
}
沒有留言:
張貼留言