Acegi框架介绍(二)

用户认证过程   Acegi支持多种方式的用户认证:如典型的基于数据库的认证、基于LDAP的认证、基于Yale中心认证等方式。不同的认证环境拥有不同的用户认证方式,现在我们先抛开这些具体的细节,考察一下Acegi对受限资源进行访问控制的典型过程:     1.你点击一个链接访问一个网页;     2.浏览器发送一个请求到服务器,服务器判断出你正在访问一个受保护的资源;     3.如果此时你并未通过身份认证,服务器发回一个响应提示你进行认证——这个响应可能是一个HTTP响应代码,抑或重定向到一个指定页面;     4.根据系统使用认证机制的不同,浏览器或者重定向到一个登录页面中,或者由浏览器通过一些其它的方式获取你的身份信息(如通过BASIC认证对话框、一个Cookie或一个X509证书);     5.浏览器再次将用户身份信息发送到服务器上(可能是一个用户登录表单的HTTP POST信息、也可能是包含认证信息的HTTP报文头);     6.服务器判断用户认证信息是否有效,如果无效,一般情况下,浏览器会要求你继续尝试,这意味着返回第3步。如果有效,则到达下一步;     7.服务器重新响应第2步所提交的原始请求,并判断该请求所访问的程序资源是否在你的权限范围内,如果你有权访问,请求将得到正确的执行并返回结果。否则,你将收到一个HTTP 403错误,这意味着你被禁止访问。     在Acegi框架里,你可以找到对应以上大多数步骤的类,其中ExceptionTranslationFilter、AuthenticationEntryPoint、AuthenticationProvider以及Acegi的认证机制是其中的代表者。     ExceptionTranslationFilter是一个Acegi的Servlet过滤器,它负责探测抛出的安全异常。当一个未认证用户访问服务器 时,Acegi将引发一个Java异常。Java异常本身对HTTP请求以及如何认证用户是一无所知 的,ExceptionTranslationFilter适时登场,对这个异常进行处理,启动用户认证的步骤(第3步)。如果已认证用户越权访问一个资 源,Acegi也将引发一个Java异常,ExceptionTranslationFilter则将这个异常转换为HTTP 403响应码(第7步)。可见,Acegi通过异常进行通讯, ExceptionTranslationFilter接收这些异常并作出相应的动作。     当ExceptionTranslationFilter通过Java异常发现用户还未认证时,它到底会将请求重定向哪个页面以要求用户提供认证信息呢? 这通过咨询AuthenticationEntryPoint来达到目的——Acegi通过AuthenticationEntryPoint描述登录页 面。     当你的浏览器通过HTTP表单或HTTP报文头向服务器提供用户认证信息时,Acegi需要将这些信息收集到Authentication中,Acegi 用“认证机制”描述这一过程。此时,这个新生成Authentication只包含用户提供的认证信息,但并未通过认证。 AuthenticationProvider 负责对Authentication进行认证。AuthenticationProvider究竟如何完成这一过程呢?请回忆一下上节我们所介绍的 UserDetails和UserDetailsService,大多数AuthenticationProvider通过 UserDetailsService获取和未认证的Authentication对应的UserDetails并进行匹配比较来完成这一任务。当用户认 证信息匹配时,Authentication被认为是有效的,AuthenticationProvider进一步将UserDetails中权限、 ACL等信息拷贝到Authentication。 当Acegi通过认证机制收集到用户认证信息并填充好Authentication后,Authentication将被保存到SecurityContextHolder中并处理用户的原始请求(第7步)。     你完全可以抛开Acegi的安全机制,编写自己的Servlet过滤器,使用自己的方案构建Authentication对象并将其放置到SecurityContextHolder中。也许你使用了CMA(Container Managed Authentication:容器管理认证),CMA允许你从ThreadLocal或JNDI中获取用户认证信息,这时你只要获取这些信息并将其转换为Authentication就可以了。   安全对象访问控制       Acegi称受保护的应用资源为“安全对象”,这包括URL资源和业务类方法。我们知道在Spring AOP中有前置增强、后置增强、异常增强和环绕增强,其中环绕增强的功能最为强大——它不但可以在目标方法被访问前拦截调用,还可以在调用返回前改变返回 的结果,甚至抛出异常。Acegi使用环绕增强对安全对象进行保护。     Acegi通过AbstractSecurityInterceptor为安全对象访问提供一致的工作模型,它按照以下流程进行工作:     1. 从SecurityContext中取出已经认证过的Authentication(包括权限信息);     2. 通过反射机制,根据目标安全对象和“配置属性”得到访问目标安全对象所需的权限;     3. AccessDecisionManager根据Authentication的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问,Acegi将抛出AccessDeniedException异常,否则到下一步; 4. 访问安全对象并获取结果(返回值或HTTP响应); 5. AbstractSecurityInterceptor可以在结果返回前进行处理:更改结果或抛出异常。  

图 6 AbstractSecurityInterceptor工作流程

    安全对象和一般对象的区别在于前者通过Acegi的“配置属性”进行了描述,如“/view.jsp=PRIV_COMMON”配置属性就将“ /view.jsp”这个URL资源标识为安全对象,它表示用户在访问/view.jsp时,必须拥有PRIV_COMMON这个权限。配置属性通过 XML配置文件,注解、数据库等方式提供。安全对象通过配置属性表示为一个权限,这样,Acegi就可以根据Authentication的权限信息获知 用户可以访问的哪些安全对象。     根据安全对象的性质以及具体实现技术,AbstractSecurityInterceptor拥有以下三个实现类:  FilterSecurityInterceptor:对URL资源的安全对象进行调用时,通过该拦截器实施环绕切面。该拦截器使用Servlet过滤器实现AOP切面,它本身就是一个Servlet过滤器;  MethodSecurityInterceptor:当调用业务类方法的安全对象时,可通过该拦截器类实施环绕切面;  AspectJSecurityInterceptor:和MethodSecurityInterceptor类似,它是针对业务类方法的拦截器,只不过它通过AspectJ实施AOP切面。

Acegi版本升级的一些重大变化      Acegi项目开始于2003年,Acegi团队在发布新版本时非常谨慎,在本书写作之时,Acegi最新版本为1.0.3。在此之前Acegi已经发布 了10多个预览版本,由于Acegi框架优异的表现,许多大型应用早在Acegi 1.0正式版本发布之前(2006年5月),就已经采用Acegi框架作为其安全访问控制的解决方案。     在Acegi社区里,来自世界各地众多优秀的安全领域专家对Acegi的改进和发展献计献策,Acegi团队广泛听取并吸收各种有益的建议,将它们融入到Acegi的框架中,使Acegi成为构建在Spring基础上企业应用的首选安全控制框架。 Acegi 1.0.3版本相比于早期预览版本发生了很大的变化,对于需要进行Acegi版本的项目来说,了解这一变化特别重要。下面,我们列出Acegi的一些重大的升级更新:  包名的更新:在0.9.0及之前的版本中,Acegi采用net.sf.acegisecurity包名前缀,在1.0.0版本之后更改为 org.acegisecurity(Hibernate也走过相同的道路,好在Acegi在正式版本发布之时就完成了这种转变);  ACL模块的调整:ACL模块发生了重大的调整,Acegi团队接收了社区大量关于ACL模块的反馈意见,重新设计了ACL模块的底层结构,在性能、封装 性、灵活性上得到了质的提升。事实上,Acegi使用org.acegisecurity.acls包代替了原来的 org.acegisecurity.acl包,后者将在后期的版本中删除,由于这种伤筋动骨的变化,将很难兼容原来ACL模块。不过,目前基于新框架的 ACL模块还没有进行充分的测试,Acegi承诺在1.1.0版本发布时提供最终的实现;  删除了ContextHolder及其相关类:在Acegi 0.9版本中,ContextHolder及其相关类被彻底从Acegi项目中删除。ContextHolder可以在多个HTTP请求中共享同一个 ThreadLocal,这和Spring提倡的ThreadLocal只应在同一线程中共享相悖。现在,Acegi使用 SecurityContextHolder替换ContextHolder,它的生命周期是一个HTTP 请求;  使用FilterChainProxy同时代理多个过滤器:在早期的版本中,Acegi通过FilterToBeanProxy将web.xml中的 Servlet过滤器定义转移到Spring容器中。这比直接在web.xml中配置Servlet过滤器要方便一些,但是Acegi框架往往需要定义多 个Servlet过滤器,使web.xml配置文件变得冗长难看。在Acegi 0.8版本中提供FilterChainProxy,它可以同时代理多个Servlet过滤器并保证过滤器的顺序。因此在新版本 中,FilterChainProxy成为推荐的选择。   

小结     Acegi是Spring项目下一个成熟的安全访问控制框架,它允许利用了Spring IoC的AOP的功能完成安全对象的访问控制。在Acegi框架中,SecurityContextHolder处于非常核心的位置,它是存放认证管理器 用户安全信息SecurityContext的“容器”,SecurityContext保存着用户安全访问控制所需的信息,直接被访问决策管理器使用。 HttpSessionContextIntegrationFilter通过在SecurityContextHolder和HttpSession中 摆渡SecurityContext,使多个请求线程可以共享同一个SecurityContext。

你可能感兴趣的:(Acegi框架介绍(二))