|
一 Filter概述
Filter 技术是servlet 2.3 新增加的功能,它新增加的功能包括: 1. 应用程序生命周期事件控制 2. 新的国际化 3. 澄清了类的装载规则; 4. 新的错误及安全属性; 5. 不赞成使用HttpUtils 类 6. 各种有用的方法 7. 阐明并扩展了几个servlet DTD 8. filter功能
其中最重要的就是filter功能。它使用户可以改变一个request和修改一个response, Filter 不是一个servlet,它不能产生一个response它能够在一个request到达servlet之前 预处理request,也可以在离开servlet时处理response。换种说法,filter其实是一个 “servlet chaining”(servlet 链)。
一个filter 包括: 1. 在servlet被调用之前截获 2. 在servlet被调用之前检查servlet request 3. 根据需要修改request头和request数据 4. 根据需要修改response头和response数据 5. 在servlet被调用之后截获
二 Filter在检修ABC系统中的应用
检修ABC系统在初期搭建框架的时候决定使用Filter来处理用户非法访问URL以及Session过期等问题。 我们首先定义了一些可以通过URL直接访问的页面,如登陆页面,重登陆页面等。当用户没有登陆而 尝试访问受保护的URL时,Filter将拦截该请求,并把访问的URL重定向到登陆页面。
在web.xml中的配置如下: <filter> <filter-name>filterservlet</filter-name> <filter-class>com.comtop.app.common.FilterServlet</filter-class> <init-param> <param-name>freePages</param-name> <param-value>
/Login.jsp;/LoginAction.do;/index.jsp;/ReLogin.jsp;/SSOLoginAction.do; </param-value> </init-param> <init-param> <param-name>toPage</param-name> <param-value>/ReLogin.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>filterservlet</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping>
<filter-mapping> <filter-name>filterservlet</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
在<filter></filter>中定义一些基本信息,比如filter的名称,filter的类以及相关初始参数。这里我 们把能直接访问的页面定义为freePages,并定义了它的值。还定义了默认的重定向页面,Relogin.jsp。 接着定义了filter-mapping,让后缀名为.do或.jsp的URL都被Filter所保护。
FilterServlet具体代码(import部分省略):
public class FilterServlet extends HttpServlet implements Filter { private FilterConfig filterConfig; private String[] freePages; private String toPage = null; private static Logger logger;
/** * 初始化filter(这里重写父类的方法) * @param filterConfig FilterConfig filter配置对象 * @throws ServletException */ public void init(FilterConfig filterConfig) throws ServletException { logger = Toolkit.getInstance().getLogger(this.getClass().getName()); int i = 0; String pages = null; StringTokenizer strTokenizer = null;
if(logger.isDebugEnabled()) { logger.debug("init validate session filter "); }
this.filterConfig = filterConfig; //以下从配置文件获取配置信息
this.toPage = filterConfig.getInitParameter("toPage"); pages = filterConfig.getInitParameter("freePages"); if(toPage == null || pages == null || toPage.trim().length() == 0 || pages.trim().length() == 0) { logger.error("web.xml中filterServlet没有配置初始化参数\"toPage\"或\"freePage\"."); throw new ServletException("web.xml中filterServlet没有配置初始化参数 \"toPage\"或\"freePage\"."); } if(logger.isDebugEnabled()) { logger.debug("toPage:" + toPage); logger.debug("freePages:" + pages); }
strTokenizer = new StringTokenizer(pages, ";"); this.freePages = new String[strTokenizer.countTokens()]; while(strTokenizer.hasMoreTokens()) { freePages[i++] = strTokenizer.nextToken(); }
if(!isFreePage(toPage)) {
logger.error("web.xml中filter初始化参数\"toPage\"的值必须是\"freePage\"中的某个页面."); throw new ServletException("web.xml中filter初始化参数\"toPage\"的值
必须是\"freePage\"中的某个页面."); } }
/** * 判断一个请求URI是否是不过滤的页面 * @param requestURI String 请求URI * @return boolean 返回true为不过滤页面 */
private boolean isFreePage(String requestURI) { boolean isFree = false; for(int i = 0; i < freePages.length; i++) { if(requestURI.endsWith(freePages[i])) { return true; } } return isFree; }
/** * 判断请求是否为有效Session * @param request ServletRequest 请求对象 * @return boolean 返回true为有效Session */ private boolean isValidSession(ServletRequest request) { HttpServletRequest httpRequest = (HttpServletRequest)request; if(httpRequest.getSession().getAttribute(GlobalConstants.SECURITY_LOGIN_KEY)
== GlobalConstants.SECURITY_IS_LOGIN) { return true; } if(logger.isDebugEnabled()) { logger.debug("Session无效,请求:" + httpRequest.getRequestURI()); } return false; }
/** * 过滤动作 * @param request ServletRequest 请求对象 * @param response ServletResponse 响应对象 * @param filterChain FilterChain 过滤器链对象 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain
filterChain) { String requestURI = null; ActionErrors errors = new ActionErrors(); ActionError errorSession = null; HttpServletRequest httpRequest = (HttpServletRequest)request; HttpServletResponse httpResponse = (HttpServletResponse)response; requestURI = httpRequest.getRequestURI();
if(logger.isDebugEnabled()) { logger.debug("Session filter RequestURI:" + requestURI); } if(!isFreePage(requestURI)) { //如果是保护页面
if(!isValidSession(request)) { //如果Session无效
String toPageURL = null; try { toPageURL = httpRequest.getContextPath() + toPage; httpResponse.encodeRedirectURL(toPageURL); httpResponse.sendRedirect(toPageURL); //转发响应
} catch(IOException ex) { logger.error("Session filter过滤时发生IO异常", ex); } } }
if(!httpResponse.isCommitted()) { //如果响应未提交,交给过滤器链
try { filterChain.doFilter(request, response); } catch(ServletException sx) { filterConfig.getServletContext().log(sx.getMessage()); } catch(IOException iox) { filterConfig.getServletContext().log(iox.getMessage()); } }
} //父类的方法
public void destroy() { } public FilterConfig getFilterConfig() { return this.filterConfig; }
public void setFilterConfig(FilterConfig filterConfig) { this.filterConfig = filterConfig; }
}
这里isFreePage方法判断用户访问的URL是否是受保护的,从配置文件中将freePages的值得到后,以分号 为隔离符将它们取出放到一个数组中,这个数组存放的每个String都是一个freePage。另外,isValidSession 方法判断在session中是否存在用户的登陆信息,如果用户未登陆,则返回false。每一个filter从doFilter()方法 中得到当前的request及response,在doFilter()方法中,以下代码完成核心判断:
if(!isFreePage(requestURI)) { //如果是保护页面
if(!isValidSession(request)) { //如果Session无效
String toPageURL = null; try { toPageURL = httpRequest.getContextPath() + toPage; httpResponse.encodeRedirectURL(toPageURL); httpResponse.sendRedirect(toPageURL); //转发响应
} catch(IOException ex) { logger.error("Session filter过滤时发生IO异常", ex); } } }
只有是通过isFreePage(requestURI)和isValidSession(request)两层验证的页面才能被访问到,基本实 现了防止用户非法访问页面的情况。在实际项目中还可以添加更多的验证方法。
|