Acegi 概述

xiaoxiao2022-06-12  36

最近根据《Spring2.x 企业应用开发详解》书中对于Acegi部门的介绍进行了学习,并整理一下学习笔记,对于初学Acegi的朋友应该是非常有帮助的,所以今天就放上来了。 [color=red]第一部分,关于Acegi概述[/color] 学习这部分对于Acegi整体上有个全面的把握,对于后续的深入学习和理解与Spring整合的相关配置是非常有帮助的。(这部分内容我也是照抄书上,只做稍微整理) Acegi Security 是一个能够为基于Spring的企业应用提供强大而灵活的安全访问控制解决方案的框架,充分利用Spring的Ioc和AOP功能,但Acegi也可以利用于非Spring的应用。 1.1 Acegi通过一下三个方面应用访问安全控制 URL资源访问控制, 能够让授权用户访问某一URL匹配模式下的对应的URL资源。Acegi通过不同功能的Servlet过滤器对URL资源进行保护,在请求受保护的URL资源前,Acegi的Servlet过滤器判断用户是否有权访问目标资源,授权者开放访问,而未被授权的用户则拒之门外。 业务方法的访问控制,Spring容器中的所有Bean的方法都可以被Acegi管理,限制只有授权用户才能访问特定方法。Acegi通过Spring AOP对容器中的Bean的受控方法进行拦截,当用户的请求引发调用Bean的受控方法时,Acegi的方法拦截器开始工作,阻止未授权者调用。 领域对象访问控制,限制只有特定的授权用户才能访问特定领域对象。对领域对象的访问控制建立在对Bean方法保护的基础上,在最终开放目标Bean方法的执行前,Acegi将检查用户的ACL(Access Control List, 访问控制列表)是否包含正要进行操作的领域对象,只有领域对象被授权时,用户才可以使用Bean方法对领域对象进行处理。此外,Acegi还可以对Bean方法的返回结果进行过滤,将一些不在当前用户访问权限范围内的领域对象剔除掉——即传统的数据可视域范围控制(使用Acegi来控制数据的可视, 还不如用动态SQL)。 1.2 Acegi体系结构 Acegi通过AuthenticationManager(认证管理器)、AcessDecisionVoter(访问控制管理器)等两个组件对象完成安全问题的处理。 SecurityContextHolder是框架级容器,保存和所有用户相关的SecurityContext实例。 SecurityContext承载着用户的身份信息和权限信息。AuthenticationManager和AcessDecisionVoter将据此进行安全访问控制。SecurityContext的认证主体信息在一个HTTP请求线程的多个调用之间通过ThreadLocal是共享的,但它不能在多个请求之间保持共享,故Acegi将认证主体信息缓存于HttpSession中,当用户请求一个受限资源时,Acegi通过HttpSessionContextIntegrationFilter将认证主体信息从HttpSession中加载到SecurityContextHolder实例中。当请求结束时HttpSessionContextIntegrationFilter执行相反操作。 (SecurityContext与HttpSession转交过程)看VSD说明更多 上图的基本说明:当用户请求一个受限资源时,AuthenticationManager首先开始工作,对用户身份进行核查,用户必须提供身份的凭证(一般为用户名和密码)。在进行身份认证时,AuthenticationManager将身份认证工作委托给多个AuthenticationProvider。多个AuthenticationProvider从各种存储中用户安全信息系统中,如数据库、CA中心、LDAP服务器。而只要一个AuthenticationProvider实例可以识别用户,哪么AuthenticationManager就能通过身份认证,并将用户授权信息放入到SecurityContext中。用户通过身份认证,试图访问某个程序时,AccessDecisionManager开始工作。AccessDecisionManager采用民主决策机制判断用户是否有权访问目标程序资源,它包含了多个AccessDecisionVoter。在访问决策时,每个AccessDecisionVoter都有投票权,AccessDecisionManager统计投票结果,并按照某种决策方式根据这些投票结果决定最终是否向用户开放受限资源。 1.3 重要的组件类 1.3.1 UserDetails 接口 UserDetails接口代表一个应用系统的用户,该接口定义了用户安全信息,如用户名、密码以及用户名和密码是否有效等信息,用户可以通过一下方法获得相关信息: String getUsername():获得用户名 String getPassword():获得密码 boolean isAccountNonExpired():用户账号是否过期 boolean isAccountNonLocked():用户账号是否锁定 boolean isCredentialsNonExpired():用户的凭证是否过期 GrantedAuthority[] getAuthorities():获得用户授权信息 1.3.2 UserDetailsService 接口 UserDetails 可能从数据库、LDAP等用户信息资源中返回,这要求有一种机制来完成这项工作,过UserDetailsService正是充当这一角色的接口。该接口仅有一个方法: UserDetails loadUserByUsername(String username) 1.3.3 Authentication 类 该类代表一个和应用程序交互的待认证用户,Acegi从类似于登陆页面、Cookie等处获取待认证的用户信息(一般是用户名和密码)并自动构造该类的实例。该类如下方法: Object getPrincipal()获取一个代表用户的对象,这个对象一般转型为:UserDetails GrantedAuthority[] getAuthorities():在Authentication被AuthenticationManager认证之前,没有任何权限信息。通过认证之后,Acegi通过UserDetails将用户权限信息加载到Authentication中,故可通过该方法获得。 注意:Authentication和UserDetails两者都有用户身份信息和权限信息。但Authentication才是Acegi进行安全访问真正使用的用户安全信息的对象,它拥有两个状态:未认证和已认证。而UserDetails是代表一个从用户安全信息资源返回的真正用户,Acegi需要从未认证的Authentication和代表真实用户信息的UserDetails进行匹配比较,当匹配成功的话,Acegi就将UserDetails中的其他安全信息(权限、ACL)。这样,Acegi安全控制组件在后续的安全访问控制中只和Authentication进行交互了。 1.3.4 SecurityContextHolder 类 该类就是存储Authentication实例的。可以通过:SecurityContextHolder.getContext().getAuthentication()获取Authentication实例。该类的方法: SecurityContext getContext()获取一个完整的安全信息上下文。而SecurityContext提供一下两个方法: Authentication getAuthentication() void setAuthentication(Authentication authentication) void setStrategyName (String strategyName)设置SecurityContext绑定模式 SecurityContextHolder类属于Acegi框架级容器对象,内部通过ThreadLocal为请求线程提供线程绑定的SecurityContext对象。由于SecurityContext是通过线程绑定机制实现的,故当主线程获得SecurityContext对象时,而主线程衍生出的新线程将无法获得该实例,过Acegi提供了一下三种绑定SecurityContext的模式: SecurityContextHolder.MODE_THREADLOCAL:将SecurityContext绑定到主线程,默认方式。 SecurityContextHolder.MODE_GLOBAL:将SecurityContext绑定到JVM中,所有线程都使用同实例。 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL:将SecurityContext绑定到主线程以及由主线程衍生的新线程。 1.3.5 ExceptionTranslationFilter 过滤器 该过滤器负责探测抛出的安全异常。当一个未认证的用户访问资源时,Acegi将引发一个异常。Java异常本身对HTTP请求以及如何认证用户一无所知的,ExceptionTranslationFilter适时登场,对这个异常进行处理,启动用户认证过程。如果已认证的用户越权访问一个资源,Acegi也将引发一个异常,此时ExceptionTranslationFilter则将这个异常转换为HTTP 403响应吗。 1.3.6 AuthenticationEntryPoint 类 当ExceptionTranslationFilter通过Java异常发现用户还未认证时,它到底会将请求重定向哪个页面以要求用户提供认证信息呢?这就必须通过咨询AuthenticationEntryPoint来达到目的——Acegi通过AuthenticationEntryPoint描述登陆页面。 1.3.7 FilterChainProxy 类 通过该代理可以同时代理多个过滤器。将Acegi在web.xml冗长的过滤器配置交由Spring或其他容器管理。 1.4 安全对象访问控制 Acegi称受保护的应用资源为“安全对象”,这包括URL资源和业务类方法。而Acegi就是根据环绕增强对安全对象进行保护。 Acegi通过AbstractSecurityInterceptor为安全对象访问提供一致的工作模型,并以以下流程工作: 从SecurityContext中取出以认证的Authentication(包括权限信息)。 通过反射机制,根据目标安全对象和“匹配属性”得到访问目标安全对象所需要的权限。 AccessDecisionManager根据Authentication的授权信息和目标安全对象所需要的权限做出是否有权访问的判断。如果无权访问,Acegi将抛出AccessDeniedException异常,否则继续下一步。 访问安全对象并获取结果(返回值或HTTP响应)。 AbstractSecurityInterceptor可以在结果返回前进行处理:更改结果或抛出异常。 安全对象和一般对象区别在于前者通过Acegi的“配置属性”进行描述,如“/save.jsp=PRIV_COMMON”配置属性将“/save.jsp”这个URL资源标识为安全对象,它表示访问这个URL资源时,必须拥有PRIV_COMMON权限。 AbstractSecurityInterceptor根据安全对象的性质,拥有以下三个实现类: FilterSecurityInterceptor:对URL资源的安全对象进行调用时,通过该拦截器实施环绕切面。该拦截器使用Servlet过滤器实现AOP切面,它本身就是一个Servlet过滤器。 MethodSecurityInterceptor:当调用业务类方法的安全对象时,可通过该拦截器类实现环绕切面。 AspectJSecurityInterceptor:和MethodSecurityInterceptor类似,它是针对业务类方法的拦截器,只是通过AspectJ实施AOP切面。 Acegi与WEB应用集成 2.1 代理Acegi的过滤器 FilterToBeanProxy使用Spring容器中的Bean代理过滤器。而FilterToBeanProxy本质上也是一个标准的过滤器。在其内部FilterToBeanProxy通过WebApplicationContext访问Spring容器,并将过滤器处理逻辑委托给一个Spring容器中的Bean。据上所述,故在web.xml文件中添加如下配置: <!-- 将所有对URL的请求,应用到该代理过滤器,并委托给Spring容器中的Bean--> <filter> <filter-name>Acegi Filter Chain Proxy</filter-name> <filter-class> org.acegisecurity.util.FilterToBeanProxy </filter-class> <init-param> <param-name>targetClass</param-name> <!-- 委托个一个过滤器链,故Spring配置文件中必须至少定义一个该类的Bean --> <param-value> org.acegisecurity.util.FilterChainProxy </param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi Filter Chain Proxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 2.2 使用代理过滤器链处理HTTP请求 Acegi通过众多的过滤器完成不同的安全控制任务。主要包括一下过滤器: HttpSessionContextIntegrationFilter ExceptionTranslationFilter ChannelProcessingFilter LogoutFilter AuthenticationProcessingFilter 当需要配置多个Servlet过滤器时,虽然可以通过FilterToBeanProxy分别进行配置,但这将导致冗长难看的web.xml,同时需要小心谨慎的通过过滤器的配置顺序来保持调用顺序。为了解决这个问题,Acegi通过FilterChainProxy同时指定多个过滤器并将他们组成一个过滤器链,而FilterToBeanProxy只要将代理目标设置为FilterChainProxy就可以了。如下是applicationContext-acegi-plugin.xml的配置: <!-- Filter Chain Proxy--> <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /**=authenticationProcessingFilter,exceptionTranslationFilter </value> </property> </bean> <!-- 认证处理器 --> <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManager" /> <property name="authenticationFailureUrl" value="/acegilogin.jsp?login_error=1" /> <property name="defaultTargetUrl" value="/userinfo.jsp" /> <property name="filterProcessesUrl" value="/j_acegi_security_check" /> </bean> 对于FilterChainProxy配置的分析: filterInvocationDefinitionSource属性由两类信息组成: 指令信息,定义了额外的操作规则,如CONVERT_URL_TO_LOWERCASE/UPPERCASE_BEFORE_COMPARISON表示判断URL匹配前将URL转化为小写或大写。 具体的资源定义信息,如PATTERN_TYPE_APACHE_ANT表示使用Ant路径风格进行匹配URL的描述,默认是用正则表达式匹配。 相关资源:敏捷开发V1.0.pptx
转载请注明原文地址: https://www.6miu.com/read-4933253.html

最新回复(0)