1、声明过滤器servlet版本 2.3引入了过滤器的概念。虽然所有支持 servlet API版本 2.3的服务器都支持过滤器,但为了使用与过滤器有关的元素,必须在 web.xml中使用版本 2.3的 DTD。过滤器可截取和修改进入一个 servlet或 JSP页面的请求或从一个 servlet或JSP页面发出的相应。在执行一个 servlet或 JSP页面之前,必须执行第一个相关的过滤器的 doFilter方法。在该过滤器对其 FilterChain对象调用doFilter时,执行链中的下一个过滤器。如果没有其他过滤器,servlet 或JSP页面被执行。过滤器具有对到来的 ServletRe
2、quest对象的全部访问权,因此,它们可以查看客户机名、查找到来的 cookie等。为了访问 servlet或 JSP页面的输出,过滤器可将响应对象包裹在一个替身对象(stand-in object)中,比方说把输出累加到一个缓冲区。在调用 FilterChain对象的 doFilter方法之后,过滤器可检查缓冲区,如有必要,就对它进行修改,然后传送到客户机。例如,程序清单 5-11帝国难以了一个简单的过滤器,只要访问相关的 servlet或 JSP页面,它就截取请求并在标准输出上打印一个报告(开发过程中在桌面系统上运行时,大多数服务器都可以使用这个过滤器)。程序清单 5-11 ReportF
3、ilter.javaJava代码 package moreservlets; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; public class ReportFilter implements Filter public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throws ServletException, IOException Ht
4、tpServletRequest req = (HttpServletRequest)request; System.out.println(req.getRemoteHost() +“ tried to access “ +req.getRequestURL() +“ on “ + new Date() + “.“); chain.doFilter(request,response); public void init(FilterConfig config)throws ServletException public void destroy() package moreservlets;
5、import java.io.*;import javax.servlet.*;import javax.servlet.http.*;import java.util.*;public class ReportFilter implements Filter public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throws ServletException, IOException HttpServletRequest req = (HttpServletRequest)
6、request;System.out.println(req.getRemoteHost() +“ tried to access “ +req.getRequestURL() +“ on “ + new Date() + “.“);chain.doFilter(request,response);public void init(FilterConfig config)throws ServletException public void destroy() 一旦建立了一个过滤器,可以在 web.xml中利用 filter元素以及 filter-name(任意名称)、file-class(完
7、全限定的类名)和(可选的)init-params子元素声明它。请注意,元素在 web.xml的 web-app元素中出现的次序不是任意的;允许服务器(但不是必需的)强制所需的次序,并且实际中有些服务器也是这样做的。但这里要注意,所有 filter元素必须出现在任意 filter-mapping元素之前, filter-mapping 元素又必须出现在所有 servlet或servlet-mapping元素之前。例如,给定上述的 ReportFilter类,可在 web.xml中作出下面的 filter声明。它把名称 Reporter与实际的类 ReportFilter(位于 moreservl
8、ets程序包中)相关联。Xml代码 Reporter moresevlets.ReportFilter Reportermoresevlets.ReportFilter一旦命名了一个过滤器,可利用 filter-mapping元素把它与一个或多个servlet或 JSP页面相关联。关于此项工作有两种选择。首先,可使用 filter-name和 servlet-name子元素把此过滤器与一个特定的servlet名(此 servlet名必须稍后在相同的 web.xml 文件中使用 servlet元素声明)关联。例如,下面的程序片断指示系统只要利用一个定制的 URL访问名为 SomeServletN
9、ame 的 servlet或 JSP页面,就运行名为 Reporter的过滤器。Xml代码 Reporter SomeServletName ReporterSomeServletName其次,可利用 filter-name和 url-pattern子元素将过滤器与一组servlet、JSP 页面或静态内容相关联。例如,相面的程序片段指示系统只要访问 Web应用中的任意 URL,就运行名为 Reporter的过滤器。Xml代码 Reporter /* Reporter/*例如,程序清单 5-12给出了将 ReportFilter过滤器与名为 PageName的servlet相关联的 web.x
10、ml文件的一部分。名字 PageName 依次又与一个名为TestPage.jsp的 JSP页面以及以模式 http: /host/webAppPrefix/UrlTest2/ 开头的 URL相关联。TestPage.jsp 的源代码已经 JSP页面命名的谈论在前面的3节“分配名称和定制的 URL“中给出。事实上,程序清单 5- 12中的 servlet和 servlet-name项从该节原封不动地拿过来的。给定这些 web.xml项,可看到下面的标准输出形式的调试报告(换行是为了容易阅读)。程序清单 5-12 Web.xml(说明 filter用法的摘录)Xml代码 Reporter mor
11、esevlets.ReportFilter Reporter PageName PageName /RealPage.jsp PageName /UrlTest2/* Reportermoresevlets.ReportFilterReporterPageNamePageName/RealPage.jspPageName /UrlTest2/*7 指定欢迎页假如用户提供了一个像 http: /host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的 URL,会发生什么事情呢?用户能得到一个目录表?一个错误?还是标准文件的内容?如果得到标准文件内容
12、,是 index.html、index.jsp、default.html、default.htm 或别的什么东西呢?Welcome-file-list 元素及其辅助的 welcome-file元素解决了这个模糊的问题。例如,下面的 web.xml项指出,如果一个 URL给出一个目录名但未给出文件名,服务器应该首先试用 index.jsp,然后再试用 index.html。如果两者都没有找到,则结果有赖于所用的服务器(如一个目录列表)。Xml代码 index.jsp index.html index.jspindex.html虽然许多服务器缺省遵循这种行为,但不一定必须这样。因此,明确地使用we
13、lcom-file-list保证可移植性是一种良好的习惯。8 指定处理错误的页面现在我了解到,你在开发 servlet和 JSP页面时从不会犯错误,而且你的所有页面是那样的清晰,一般的程序员都不会被它们的搞糊涂。但是,是人总会犯错误的,用户可能会提供不合规定的参数,使用不正确的 URL或者不能提供必需的表单字段值。除此之外,其它开发人员可能不那么细心,他们应该有些工具来克服自己的不足。error-page元素就是用来克服这些问题的。它有两个可能的子元素,分别是:error-code和 exception- type。第一个子元素 error-code指出在给定的HTTP错误代码出现时使用的 U
14、RL。第二个子元素 excpetion-type指出在出现某个给定的 Java异常但未捕捉到时使用的 URL。error-code 和 exception-type都利用 location元素指出相应的 URL。此 URL 必须以/开始。location 所指出的位置处的页面可通过查找 HttpServletRequest对象的两个专门的属性来访问关于错误的信息,这两个属性分别是:javax.servlet.error.status_code 和javax.servlet.error.message。可回忆一下,在 web.xml内以正确的次序声明 web-app的子元素很重要。这里只要记住,
15、error-page 出现在 web.xml文件的末尾附近,servlet、servlet-name和 welcome-file-list之后即可。8.1 error-code元素为了更好地了解 error-code元素的值,可考虑一下如果不正确地输入文件名,大多数站点会作出什么反映。这样做一般会出现一个 404错误信息,它表示不能找到该文件,但几乎没提供更多有用的信息。另一方面,可以试一下在http:/ 处或者特别是在http:/ 处输出未知的文件名。这是会得出有用的消息,这些消息提供可选择的位置,以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上 rm-er
16、ror-page子元素)。由 form-login-page给出的 HTML表单必须具有一个 j_security_check的 ACTION 属性、一个名为 j_username的用户名文本字段以及一个名为 j_password的口令字段。例如,程序清单 5-19指示服务器使用基于表单的验证。Web 应用的顶层目录中的一个名为 login.jsp的页面将收集用户名和口令,并且失败的登陆将由相同目录中名为 login-error.jsp的页面报告。程序清单 5-19 web.xml(说明 login-config的摘录)Xml代码 . FORM /login.jsp /login-error.
17、jsp . FORM /login.jsp/login-error.jsp9.2 限制对 Web资源的访问现在,可以指示服务器使用何种验证方法了。“了不起,“你说道,“除非我能指定一个来收到保护的 URL,否则没有多大用处。“没错。指出这些 URL并说明他们应该得到何种保护正是 security-constriaint元素的用途。此元素在 web.xml中应该出现在 login-config的紧前面。它包含是个可能的子元素,分别是:web-resource-collection、 auth-constraint、user-data-constraint和 display-name。下面各小节对
18、它们进行介绍。l web-resource-collection此元素确定应该保护的资源。所有 security-constraint元素都必须包含至少一个 web-resource-collection项。此元素由一个给出任意标识名称的 web-resource-name元素、一个确定应该保护的 URL的 url-pattern元素、一个指出此保护所适用的 HTTP 命令(GET、POST 等,缺省为所有方法)的 http-method元素和一个提供资料的可选 description元素组成。例如,下面的 Web-resource-collection项(在 security-constra
19、tint元素内)指出 Web应用的 proprietary目录中所有文档应该受到保护。Xml代码 Proprietary /propritary/* Proprietary/propritary/*重要的是应该注意到,url-pattern 仅适用于直接访问这些资源的客户机。特别是,它不适合于通过 MVC体系结构利用 RequestDispatcher 来访问的页面,或者不适合于利用类似 jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如,servlet 可利用 MVC体系结构查找数据,把它放到 bean中,发送请求到从 bean中提取数据的 JSP页面并显示它
20、。我们希望保证决不直接访问受保护的 JSP页面,而只是通过建立该页面将使用的 bean的servlet来访问它。url-pattern 和 auth-contraint元素可通过声明不允许任何用户直接访问 JSP页面来提供这种保证。但是,这种不匀称的行为可能让开发人员放松警惕,使他们偶然对应受保护的资源提供不受限制的访问。 l auth-constraint尽管 web-resource-collention元素质出了哪些 URL应该受到保护,但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别 role- name
21、元素,以及包含(可选)一个描述角色的 description元素。例如,下面 web.xml中的security-constraint元素部门规定只有指定为 Administrator或 Big Kahuna(或两者)的用户具有指定资源的访问权。Xml代码 . administrator kahuna . administratorkahuna重要的是认识到,到此为止,这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令,完全有赖于具体的系统。例如,Tomcat 使用 install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关
22、联,正如下面例子中所示,它指出用户 joe(口令 bigshot)和jane(口令 enaj)属于 administrator和 kahuna角色。Xml代码 l user-data-constraint这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素(合法值为 NONE、 INTEGRAL 或 CONFIDENTIAL),并且可选地包含一个 description元素。transport-guarantee 为 NONE值将对所用的通讯协议不加限制。INTEGRAL 值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上
23、(并且在未来的 HTTP版本中),在 INTEGRAL 和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL。例如,下面指示服务器只允许对相关资源做 HTTPS 连接:Xml代码 CONFIDENTIAL CONFIDENTIALl display-namesecurity-constraint的这个很少使用的子元素给予可能由 GUI工具使用的安全约束项一个名称。9.3 分配角色名迄今为止,讨论已经集中到完全由容器(服务器)处理的安全问题之上了。但servlet以及 JSP页面也能够处理它们自己的安全问题。例如,容器可能允许用户从 bigwig或 bigch
24、eese角色访问一个显示主管人员额外紧贴的页面,但只允许 bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用 HttpServletRequset的 isUserInRole方法,并据此修改访问。Servlet的 security-role-ref 子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如,假如编写了一个调用 request.isUserInRole(“boss“)的 servlet,但后来该 servlet被用在了一个其口令文件调用角色 manager而不是 boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。Xm
25、l代码 boss manager boss manager 也可以在 web-app内利用 security-role元素提供将出现在 role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级 IDE容易处理安全信息。10 控制会话超时如果某个会话在一定的时间内未被访问,服务器可把它扔掉以节约内存。可利用 HttpSession的 setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法,则缺省的超时值由具体的服务器决定。但可利用session-config和 session- timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟,因此,下面的例子设置缺省会话超时值为三个小时(180 分钟)。