您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > Spring in Action 2nd(第7章下)
第7章保护Spring续表org.acegisecurity.*securechannel.ChannelProcessingFilter确保正通过HTTP或HTTPS发送一个请求(按照需求的要求)。ui.basicauth.BasicProcessingFilter尝试通过处理一个HTTP基本身份验证来验证一个用户的身份。ui.cas.CasProcessingFilter通过处理CAS(中央认证服务)权证来验证一个用户的身份。ui.digestauth.DigestProcessingFilter尝试通过处理一个HTTP摘要身份验证来验证一个用户的身份。ui.ExceptionTranslationFilter处理当前过滤器链中其他任何过滤器所抛出的任一AccessDeniedException或AuthenticationException。ui.logout.LogoutFilter用于将一个用户退出当前应用程序。ui.rememberme.RememberMeProcessingFilter自动验证已要求当前应用程序“记住”的用户身份。ui.switchuser.SwitchUserProcessingFilter用于断开某个用户。提供的功能与Unix的su相似。ui.webapp.AuthenticationProcessingFilter接受当前用户的主体和凭证,并尝试验证该用户的身份。ui.webapp.SiteminderAuthenticationProcessingFilter通过处理CA/NetegritySiteMinder标题来验证一个用户的身份。ui.x509.X509ProcessingFilter通过处理一个客户端Web浏览器提交的X.509证书来验证一个用户的身份。wrapper.SecurityContextHolderAwareRequestFilter为servlet请求增加一个请求外壳。尽管表7.4列出了SpringSecurity提供的17种过滤器,但是对于绝大多数应用程序来说,只使用它们中的少数几个便已足够。特别地,在对一个Spring保护的Web应用程序提出请求时,它将经过至少下列四个过滤器(如图7.7所示):1.由于HTTP本身没有国界,因此SpringSecurity需要以某种方式在Web请求之间保留一个用户的身份验证。集成过滤器负责在一个请求的开始时检索先前存储的认证信息(通常存储在HTTP会话中),为SpringSecurity的其他过滤器进行处理做好准备。2.接下来,某个认证处理过滤器将决定该请求是否是一个认证请求。如果是,有关的用户信息(通常为用户名/密码)就会被从这个请求中提取出来,然后转交给认证管理器来确定用户的身份。如果这不是一个认证请求,那么认证处理过滤器不会执行任何处理,而该请求则会继续沿着过滤器链向下移动。3.接下来的过滤器是例外转换过滤器。例外转换过滤器存在的唯一用途就是将可能已经被抛出的AccessDeniedException和AuthenticationException转换成适当的HTTP响应。如果检测到一个AuthenticationException,那么当前请求就会被发送到一个身份验证入口点(举例来说,登录界面)。如果被抛出的是一个AccessDeniedException,那么默认的行为将是向当前浏览器返回一个HTTP403错误。4.所需的昀后一个过滤器是过滤器安全拦截器。这个过滤器充当Web应用程序的安全拦截器(见7.1.1)。它的工作是检查这个请求,然后确定当前用户是否具有访问被保护资源所必需的权限。不过,它并不是单独工作,它主要依靠认证管理器和访问决策管理器来帮助它授予或制止对被保护资源的访问。图7.7一个请求通过SpringSecurity核心过滤器的流程。7.4保护Web应用程序如果当前用户成功通过了过滤器安全拦截器,那么他/她便将被授权可以访问那个受保护的Web资源。否则,将抛出一个AccessDeniedException,然后例外转换过滤器就会对它进行适当处理。我们将逐一仔细研究这些过滤器。但是在能够开始使用它们之前,你还需要理解SpringSecurity是如何对Servlet过滤器使用一个Spring风格的技巧的。7.4.1SpringSecurity如果你曾经使用过Servlet过滤器,那么你知道要让它们生效,就必须在Web应用程序的web.xml文件中使用filter和filter-mapping元素配置它们。虽然这样做能起作用,但是它并不适用于使用依赖注入进行的配置。举例来说,假设你在自己的web.xml文件中声明了以下过滤器:现在,假设那个FooFilter需要引用一个BarBean来完成它的工作。你该如何向FooFilter中注入Bar的一个实例呢?简单的回答是:你无法做到这一点。web.xml文件没有依赖注入的概念,也没有直接的方式可以从Spring应用程序上下文中获取Bean,然后将它们装配到一个servlet过滤器中。唯一可以选择的办法就是使用Spring的WebApplicationContextUtils从Spring上下文中获取所需的barBean。举例来说,你可能会在那个过滤器的代码中加入以下内容:不过,这种方法的问题是你必须在自己的Servlet过滤器中编写Spring特定的代码。此外,你在结束时还要硬编码一个指向那个barBean名称的引用。幸运的是,SpringSecurity通过FilterToBeanProxy提供了一种更好的办法。FilterToBeanProxy是一个特殊的Servlet过滤器,它本身做的工作并不多,而是将自己的工作委托给Spring应用程序上下文中的一个Bean来完成(如图7.8所示)。被委托的Bean几乎和其他的Servlet过滤器一样,实现javax.servlet.Filter接口,但它是在Spring配置文件而不是web.xml文件中配置的。图7.8FilterToBeanProxy把过滤器处理代理给Spring应用程序上下文中的一个委托过滤器Bean。通过使用FilterToBeanProxy,就可以在Spring中配置实际的过滤器,充分利用Spring支持依赖注入的优势。这里的web.xml文件只包含FilterToBeanProxy的filter声明。实际的FooFilter是在Spring配置文件中配置的,并且它使用设置方法注入(setterinjection)将一个对BarBean的引用设置到bar属性中。要使用FilterToBeanProxy,必须在Web应用程序的web.xml文件中建立一个filter条目。举例来说,第7章保护Spring如果正在使用FilterToBeanProxy配置一个FooFilter,则可能应该使用以下代码:在这里,targetClass初始化参数被设置为所委托过滤器Bean的完全匹配类名。当这个FilterToBeanProxy被初始化时,它会在Spring上下文中查找一个类型为FooFilter的Bean,并且把自已的过滤工作委托给在Spring上下文中找到的FooFilterBean来完成:如果找不到FooFilterBean,则会抛出一个异常。如果找到了一个以上匹配的Bean,则会使用第一个找到的Bean。可选地,你也可以通过设置targetBean初始化参数(而不是targetClass)来从Spring上下文中选取一个特定的Bean。举例来说,按照以下方式设置targetBean属性后,就可以根据名字挑选出fooFilterBean来:这里的targetBean初始化参数使得可以更具体地指定将过滤工作委托给哪个Bean来完成,但是需要精确匹配web.xml和Spring配置文件中受委托Bean的名字。如果决定重新命名那个Bean时,就会带来额外的工作量。出于这个原因,使用targetClass(而不是targetBean)很可能是更好的选择。昀后,你将需要把那个过滤器与一个URL模式相关联。下面的filter-mapping将FilterToBeanProxy的这个Foo实例与/*的一个URL模式连接在一起,从而所有的请求都得以被处理:7.4保护Web应用程序不管你选择的是targetClass还是targetBean,FilterToBeanProxy都必须能够访问这个Spring应用程序上下文。这意味着这个Spring上下文必须使用Spring的ContextLoaderListener或者是ContextLoaderServlet进行加载(见第13章)。既然已经知道FilterToBeanProxy是如何工作的了,那么目前昀吸引人的问题就是:为什么所有这些工作都不得不和SpringSecurity一起完成呢?这个问题很有意义。正如本书前面提到的那样,SpringSecurity在实施Web安全措施时使用Servlet过滤器。这些过滤器中的每一个都必须被注入来自Spring应用程序上下文的其他Bean,以完成它们的工作。比如说,FilterSecurityInterceptor需要被注入AuthenticationManager和AccessDecisionManager,那样它才能实施安全措施。不幸的是,Servlet规范并没有使得Servlet过滤器上的依赖注入工作容易进行。FilterToBeanProxy通过充当在Spring应用程序上下文中被配置为bean的实际过滤器的“挂名人物”来解决这个问题。现在你可能正觉得奇怪,如果FilterToBeanProxy通过代理给一个Spring配置的Bean来处理请求,那么在接收端(即Spring端)是什么情况呢?那是一个极好的问题。实际上,FilterToBeanProxy代理给的那个Bean可以是javax.servlet.Filter的任意实现。这可以是SpringSecurity的任何一个过滤器,或者它可以是你自己创建的一个过滤器。但是正如本书已经提到的那样,SpringSecurity要求至少配置四个而且可能一打或者更多的过滤器。这是否意味着你必须为每一个SpringSecurity的过滤器配置一个FilterTo-BeanProxy呢?当然不是。虽然肯定可以向web.xml文件添加数个FilterToBeanProxy(每个SpringSecurity过滤器一个),但是那样将会有特别多的XML要编写。为了使生活更加轻松一些,SpringSecurity提供了FilterToBeanProxy的同伴——FilterChainProxy。FilterChainProxy是javax.servlet.Filter的一个实现,它可以被配置来同时把几个过滤器链接在一起,如图7.9所示。图7.9FilterChainProxy将多个过滤器链接在一起代表FilterToBeanProxy。FilterBeanProxy拦截来自客户端的请求,然后把它发送给FilterChainProxy进行处理。FilterChainProxy接着让那个请求通过一个或者是多个在Spring应用程序上下文中配置的过滤器。FilterChainProxy在Spring应用程序上下文中像下面那样配置:第7章保护Spring这里的filterInvocationDefinitionSource属性的值为一个String,它被解析为FilterChainProxy将用来把过滤器链接到一起的一种模式。在这个示例中,第一行告诉FilterChainProxy在比较URL模式之前,先把它们统一为小写字母。接下来一行说,在声明URL模式时,将使用ApacheAnt样式路径。昀后,一个或多个“URL-到-过滤器-链”映像将被提供。在这里,/**模式(在Ant中,这意味着所有URL都将匹配)被映像给三个过滤器。被配置为filter1Bean的那个过滤器
本文标题:Spring in Action 2nd(第7章下)
链接地址:https://www.777doc.com/doc-5317504 .html