设置站点黑名单的过滤器(BannedAccessFilter)

    本系列文章导读:

        通用的用户登录过滤器(SessionFilter)

        设置不使用缓存的过滤器(ClearCacheFilter)

        设置站点黑名单的过滤器(BannedAccessFilter)

        将响应数据进行压缩处理的过滤器(CompressionFilter)

        替换禁用语(指定关键字)的过滤器(StopWordsFilter)

功能描述

        不允许从禁用的站点(IP)访问当前应用,也不允许从禁用的站点链接到当前应用。
        为了简单起见,设置禁用站点时,暂不支持使用通配符。只是抛砖引玉了。
        比如:禁止其他的网站引用本站的图片资源,只需在此基础上稍作修改即可。

使用方法

        在 java web 项目的 web.xml 文件中添加如下代码。

 <!--设置站点黑名单的过滤器配置  开始 -->
 <filter>
  <filter-name>BannedAccessFilter</filter-name>
  <filter-class>com.hmw.filter.BannedAccessFilter</filter-class>
  <init-param>
      <description>需要禁用的站点,一个站点占用一行</description>
      <param-name>bannedSites</param-name>
      <param-value>
          192.168.1.101
          192.168.1.102
          www.csdn.net
      </param-value>
  </init-param>
 </filter>
 
 <filter-mapping>
  <filter-name>BannedAccessFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 <!--设置站点黑名单的过滤器配置  结束 -->

过滤器源码

package com.hmw.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

/**
 * 设置禁用站点(黑名单)的过滤器
 * @author 何明旺
 */
public class BannedAccessFilter implements Filter {
    static final Logger logger = Logger.getLogger(BannedAccessFilter.class);
    
	private HashSet bannedSiteTable;
	
	/**
	 * 将配置的禁用站点列表初始化到一个 HashSet 中
	 */
	@Override
	public void init(FilterConfig config) throws ServletException {
		bannedSiteTable = new HashSet();
		String bannedSites = config.getInitParameter("bannedSites");
		// Default token set: white space.
		StringTokenizer tok = new StringTokenizer(bannedSites);
		while (tok.hasMoreTokens()) {
			String bannedSite = tok.nextToken();
			bannedSiteTable.add(bannedSite);
			logger.info("Banned " + bannedSite);
		}
	}
	
	/**
	 * 如果请求来自被禁用的站点,或是从被禁用的站点链接过来的,则拒绝访问。
	 */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
		logger.debug("BannedAccessFilter: Filtering the Request...");
		
		HttpServletRequest req = (HttpServletRequest) request;
		String requestingHost = req.getRemoteHost();
		String referringHost = getReferringHost(req.getHeader("Referer"));
		
		String bannedSite = null;
		boolean isBanned = false;
		if (bannedSiteTable.contains(requestingHost)) {
			bannedSite = requestingHost;
			isBanned = true;
		} else if (bannedSiteTable.contains(referringHost)) {
			bannedSite = referringHost;
			isBanned = true;
		}
		
		if (isBanned) {
			showWarning(response, bannedSite);
		} else {
			chain.doFilter(request, response);
		}
		
		logger.debug("BannedAccessFilter: Filtering the Response...");
	}

	@Override
	public void destroy() {
	}

	/**
	 * 根据 URL 链接地址,取得该链接地址所在的站点
	 * @param refererringURLString URL链接地址
	 * @return 该 URL 链接地址所在的站点,如果传入的参数不是一个符合URL规范的字符串,则返回 null
	 */
	private String getReferringHost(String refererringURLString) {
	    if(StringUtils.isBlank(refererringURLString))
	        return null;
	    
		try {
			URL referringURL = new URL(refererringURLString);
			return referringURL.getHost();
		} catch (MalformedURLException mue) { // Malformed
			return null;
		}
	}

	/**
	 * 如果用户是从禁用站点访问的该应用,或是从禁用站点链接过来的,则调用此方法将警告信息展现给用户。
	 * @param response HTTP请求响应对象
	 * @param bannedSite 禁止的站点
	 * @throws ServletException
	 * @throws IOException
	 * @author 何明旺
	 */
	private void showWarning(ServletResponse response, String bannedSite) throws ServletException, IOException {
	    String htmlCode  = "";
	    htmlCode += "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
	    htmlCode += "<html xmlns=\"http://www.w3.org/1999/xhtml\">";
	    htmlCode += "  <head>";
	    htmlCode += "      <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />";
	    htmlCode += "      <title>禁止访问</title>";
	    htmlCode += "  </head>";
	    htmlCode += "  <body>";
	    htmlCode += "      <h1>禁止访问</h1>";
	    htmlCode += "      <p>对不起,您无法访问该资源,因为您的站点已经被列入我们的黑名单!</p>";
	    htmlCode += "      <p>您的站点是:<strong>" + bannedSite + "</strong></p>";
	    htmlCode += "  </body>";
	    htmlCode += "</html>";

	    response.setContentType("text/html");
	    PrintWriter out = null;
	    try{
	        out = response.getWriter();
    		out.println(htmlCode);
	    }finally{
    	      if(out != null){
    	        out.flush();
    	        out.close();
    	      }
    	}
    	
    	/*
    	 * 也可以使用下面的方法直接转发或重定向到指定的警告页面
    	 * 转发:
    	 *     ((HttpServletRequest)request).getRequestDispatcher("/warn.html").forward(request, response);
    	 * 重定向:
    	 *     ((HttpServletResponse)response).sendRedirect("webAppContext/warn.html");
    	 */
	}
}
posted @ 2012-01-11 11:59  星情  阅读(2758)  评论(0编辑  收藏  举报
欢迎阅读旺仔的更多文章:旺仔专栏文章索引