黑名单设计
目标:实现黑名单机制,防止网络游戏爬虫
public class BlackListFilter implements Filter, ApplicationContextAware { private final static Logger LOG = LoggerFactory.getLogger(BlackListFilter.class); private WConfigService wConfigService; private JedisClient jedisClient; private static Map<String, Integer> queue = Maps.newConcurrentMap(); private final static String WISH_LIST_BLACK_LIST_CACHE = "wish_list_black_list_cache"; private final static int EXPIRE_TIME = 24 * 60 * 60; private final static String UN_KNOW = "unknown"; private final static String WCONFIG_NAME = "wConfigService"; private final static String JEDIS_NAME = "jedisClient"; private static ApplicationContext ctx; @Override public void init(FilterConfig filterConfig) throws ServletException { } private void init() { if (ctx != null && ctx.getBean(WCONFIG_NAME) != null && wConfigService == null) { wConfigService = (WConfigService) ctx.getBean(WCONFIG_NAME); } if (ctx != null && ctx.getBean(JEDIS_NAME) != null && jedisClient == null) { jedisClient = (JedisClient) ctx.getBean(JEDIS_NAME); } } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //防止NPE if (Objects.isNull(wConfigService) || Objects.isNull(jedisClient)) { init(); filterChain.doFilter(servletRequest, servletResponse); return; } //开关关闭 if (!wConfigService.obtainBlackListIsWork()) { filterChain.doFilter(servletRequest, servletResponse); return; } try { String ip = getIp(servletRequest); if (StringUtils.isBlank(ip)) { LOG.error("没有找到客户端ip"); filterChain.doFilter(servletRequest, servletResponse); return; } //判断是否在黑名单内 String blackListCache = Objects.nonNull(jedisClient.get(WISH_LIST_BLACK_LIST_CACHE)) ? jedisClient.get(WISH_LIST_BLACK_LIST_CACHE) : ""; List<String> blackList = CollectionUtils.isNotEmpty(JsonUtil.ofList(blackListCache, String.class)) ? JsonUtil.ofList(blackListCache, String.class) : Lists.newArrayList(); if (blackList.contains(ip)) { LOG.info("系统拒绝ip:" + ip + "的访问!"); throw new IllegalArgumentException(); } int count = 0; if (queue.keySet().contains(ip)) { count = queue.get(ip); count++; queue.put(ip, count); } else { count++; queue.put(ip, count); } int limitCount = Integer.valueOf(wConfigService.obtainBlackListLimitCount()); if (count >= limitCount) { synchronized (this) { queue.remove(ip); //超过访问次数限制,加入黑名单 if (CollectionUtils.isEmpty(blackList)) { //清除昨天的历史记录 queue = Maps.newConcurrentMap(); //第一次加入黑名单 blackList = Lists.newArrayList(); blackList.add(ip); jedisClient.set(WISH_LIST_BLACK_LIST_CACHE, JsonUtil.toJson(blackList)); jedisClient.expire(WISH_LIST_BLACK_LIST_CACHE, EXPIRE_TIME); } else { //黑名单增加ip blackList.add(ip); jedisClient.set(WISH_LIST_BLACK_LIST_CACHE, JsonUtil.toJson(blackList)); } filterChain.doFilter(servletRequest, servletResponse); } } else { filterChain.doFilter(servletRequest, servletResponse); } } catch (IllegalArgumentException e) { throw new IllegalArgumentException("今天的心愿太多了,请明天再来吧!"); } catch (Exception e) { LOG.error("黑名单过滤数据异常"); filterChain.doFilter(servletRequest, servletResponse); } } private String getIp(ServletRequest servletRequest) { String ip = ""; try { if (servletRequest instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) servletRequest; String ipAddresses = request.getHeader("x-forwarded-for"); if (ipAddresses == null || ipAddresses.length() == 0 || UN_KNOW.equalsIgnoreCase(ipAddresses)) { //Proxy-Client-IP:apache 服务代理 ipAddresses = request.getHeader("Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || UN_KNOW.equalsIgnoreCase(ipAddresses)) { //WL-Proxy-Client-IP:weblogic 服务代理 ipAddresses = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || UN_KNOW.equalsIgnoreCase(ipAddresses)) { //HTTP_CLIENT_IP:有些代理服务器 ipAddresses = request.getHeader("HTTP_CLIENT_IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || UN_KNOW.equalsIgnoreCase(ipAddresses)) { //X-Real-IP:nginx服务代理 ipAddresses = request.getHeader("X-Real-IP"); } //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP if (ipAddresses != null && ipAddresses.length() != 0) { ip = ipAddresses.split(",")[0]; } //还是不能获取到,最后再通过request.getRemoteAddr();获取 if (ip == null || ip.length() == 0 || UN_KNOW.equalsIgnoreCase(ipAddresses)) { ip = request.getRemoteAddr(); } } } catch (Exception e) { ip = ""; LOG.info("获取ip失败,失败原因:" + e.getMessage()); } return ip; } @Override public void destroy() { } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { BlackListFilter.ctx = applicationContext; } }