黑名单设计

目标:实现黑名单机制,防止网络游戏爬虫

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;
    }
}
原文地址:https://www.cnblogs.com/zhangchiblog/p/10907497.html