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(); } } }*/ } } }
沒有留言:
張貼留言