用户认证过程 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。
点赞
评论