Acegi学习二

组成  

Acegi安全框架主要由安全管理对象、拦截器以及安全控制管理组件组成。安全管理对象是系统可以进行安全控制的实体,Acegi框架主要支持方法和URL请求两类安全管理对象;拦截器是Acegi中的重要部件,用来实现安全控制请求的拦截,针对不同的安全管理对象的安全控制请求使用不同的拦截器进行拦截;安全控制管理部件是实际实现各种安全控制的组件,对被拦截器拦截的请求进行安全管理与控制,主要组件包括实现用户身份认证的AuthenticationManager、实现用户授权的AccessDecisionManager 以及实现角色转换的RunAsManager。安全管理对象、拦截器以及安全控制管理组件三者关系如图1所示

数据库

authorities

  `AUTH_ID` int(11) NOT NULL default '0',

  `AUTHORITY` varchar(255) NOT NULL,

  `AUTH_TYPE` varchar(32) NOT NULL,

  `PROTECTED_RES` varchar(64) NOT NULL,

  `DISPLAY` varchar(64) NOT NULL,

  `NOTE` varchar(64) default NULL,

  PRIMARY KEY  (`AUTH_ID`),

  UNIQUE KEY `AUTH_ID` (`AUTH_ID`)

)

这个表设置了用户可以使用的资源。AUTHORITYPROTECTED_RES应用系统中需要控制访问权限的方法

contacts

  `ID` int(11) NOT NULL auto_increment,

  `CONTACT_NAME` varchar(50) NOT NULL,

  `EMAIL` varchar(50) default NULL,

  PRIMARY KEY  (`ID`),

  UNIQUE KEY `ID` (`ID`)

)

应用数据表

userinfo

  `USER_ID` int(11) NOT NULL auto_increment,

  `USERNAME` varchar(10) NOT NULL,

  `PASSWORD` varchar(30) default NULL,

  `ENABLED` tinyint(1) NOT NULL default '0',

  PRIMARY KEY  (`USER_ID`),

  UNIQUE KEY `USER_ID` (`USER_ID`),

  UNIQUE KEY `USERNAME` (`USERNAME`)

)

用户信息表,用户密码

配置文件

 

Web.xml

 

指定了acegi的配置文件位置

<context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>

      /WEB-INF/applicationContext-basic.xml

      /WEB-INF/applicationContext-security-acegi.xml

    </param-value>

  </context-param>

 

②将过滤器委托给FilterChainProxy
    
    

 <filter>

    <filter-name>Acegi Filter Chain Proxy</filter-name>

    <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>

    <init-param>

      <param-name>targetClass</param-name>

      <param-value>org.acegisecurity.util.FilterChainProxy</param-value>

    </init-param>

  </filter>

 

>③对所有的URL进行过滤
    
    

 

  <filter-mapping>

    <filter-name>Acegi Filter Chain Proxy</filter-name>

    <url-pattern>/*</url-pattern>

  </filter-mapping>

 

<listener>

    <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>

  </listener>

 

另外还配置了日志文件和spring

 

FilterToBeanProxy   Acegi通过实现了Filter接口的FilterToBeanProxy提供一种特殊的使用Servlet Filter的方式,它委托Spring中的Bean -- FilterChainProxy来完成过滤功能,这好处是简化了web.xml的配置,并且充分利用了Spring IOC的优势。FilterChainProxy包含了处理认证过程的filter列表,每个filter都有各自的功能。

    <filter>

        <filter-name>Acegi Filter Chain Proxy</filter-name>

        <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>

        <init-param>

            <param-name>targetClass</param-name>

            <param-value>org.acegisecurity.util.FilterChainProxy</param-value>

        </init-param>

    </filter>

 

2) filter-mapping   <filter-mapping>限定了FilterToBeanProxyURL匹配模式,只有*.do*.jsp/j_acegi_security_check 的请求才会受到权限控制,对javascript,css等不限制。

   <filter-mapping>

      <filter-name>Acegi Filter Chain Proxy</filter-name>

      <url-pattern>*.do</url-pattern>

    </filter-mapping>

    

    <filter-mapping>

      <filter-name>Acegi Filter Chain Proxy</filter-name>

      <url-pattern>*.jsp</url-pattern>

    </filter-mapping>

    

    <filter-mapping>

      <filter-name>Acegi Filter Chain Proxy</filter-name>

      <url-pattern>/j_acegi_security_check</url-pattern>

    </filter-mapping>

3) HttpSessionEventPublisher   <listener>HttpSessionEventPublisher用于发布 HttpSessionApplicationEventsHttpSessionDestroyedEvent事件给spring applicationcontext

    <listener>

        <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>

    </listener>

 

 

applicationContext-basic.xml

 

bean 配置中,需要关注的几个关键bean,在后面的扩展中需要用到:  1 AuthenticationManager 用于认证ContextHolder中的Authentication对象。给多种的认证方式留下了接口。

2 AccessDecissionManager 用于授权一个特定的操作,这里有一个授权策略问题,三个实现类分别为:     AffirmativeBased 只需有一个投票赞成即可通过(最常用);allowIfAllAbstainDecisions属性值默认为false,意思是如果所有的授权投票是都是弃权,则通不过授权检查。     ConsensusBased 需要大多数投票赞成即可通过;     UnanimousBased 需要所有的投票赞成才能通过(悲观吧)。

3 ObjectDefinitionSource 描述角色与资源的匹配方式。

首先配置了数据库德访问

 

配置决策的策略

<bean id="businessAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">

     <property name="allowIfAllAbstainDecisions"><value>false</value></property>

     <property name="decisionVoters">

        <list>

           <ref bean="roleVoter"/>

        </list>

     </property>

  </bean>

 

例子的数据库访问

  <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">

    <property name="customEditors">

      <map>

        <entry key="org.acegisecurity.intercept.method.MethodDefinitionSource">

          <bean class="sample.util.DataSourceMethodDefinitionSourceEditor">

            <property name="jdbcTemplate"> <ref bean="jdbcTemplate"/> </property>

          </bean>

        </entry>

      </map>

    </property>

  </bean>

 

<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">

      <property name="transactionManager"><ref bean="transactionManager"/></property>

    <property name="transactionAttributeSource">

      <value>

        sample.service.impl.ContactManager.*=PROPAGATION_REQUIRED

      </value>

    </property>

  </bean>

 

  <!--dao start -->

  <bean id="contactDao" class="sample.dao.impl.ContactDao">

    <property name="dataSource">

      <ref bean="dataSource"/>

    </property>

  </bean>

 

  <!--service start -->

  <bean id="contactManagerTarget" class="sample.service.impl.ContactManager" >

    <property name="contactDao">

      <ref bean="contactDao"/>

    </property>

  </bean>

 

 

把应用系统需要控制权限的配置信息和处理程序关联

<bean id="contactManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">

     <property name="authenticationManager"><ref bean="authenticationManager"/></property>

     <property name="accessDecisionManager"><ref bean="businessAccessDecisionManager"/></property>

     <property name="objectDefinitionSource">

        <value>

          select authority,PROTECTED_RES from authorities where AUTH_TYPE='FUNCTION' and authority like 'AUTH_FUNC_ContactManager%'

        </value>

     </property>

  </bean>

 

相当于一个代理类来访问

<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">

     <property name="proxyInterfaces"><value>sample.service.IContactManager</value></property>

     <property name="interceptorNames">

        <list>

           <idref local="transactionInterceptor"/>

           <idref local="contactManagerSecurity"/>

           <idref local="contactManagerTarget"/>

        </list>

     </property>

  </bean>

 

 

applicationContext-security-acegi.xml

设定过滤器

<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">

      <property name="filterInvocationDefinitionSource">

         <value>

           CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

           PATTERN_TYPE_APACHE_ANT

              /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,anonymousProcessingFilter,basicProcessingFilter

         </value>

      </property>

</bean>

 

 

<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">

     <property name="context"><value>org.acegisecurity.captcha.CaptchaSecurityContextImpl</value></property>

  </bean>

 

/*配置认证管理器*/

②认证管理器
    
    

 

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">

      <property name="providers">

-1使用基于DAO的认证提供者提供认证服务
    
    

 

         <list>

            <ref local="daoAuthenticationProvider"/>

           <ref local="anonymousAuthenticationProvider"/>

         </list>

      </property>

   </bean>

 

得到配置信息

 

<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">

     <property name="dataSource"><ref bean="dataSource"/></property>

     <property name="usersByUsernameQuery">

       <value>SELECT USERNAME, PASSWORD,ENABLED FROM USERINFO WHERE USERNAME=?</value>

     </property>

     <property name="authoritiesByUsernameQuery">

       <value>

         SELECT username,authority FROM `userinfo` u, `authorities` a,`user_auth` ua

         WHERE u.user_id=ua.user_id

         and a.auth_id=ua.auth_id

         and u.username = ?

       </value>

     </property>

   </bean>

 

缓存

 

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>

 

  <bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">

     <property name="cacheManager"> <ref local="cacheManager"/> </property>

     <property name="cacheName"> <value>userCache</value> </property>

  </bean>

/*配置缓存有效时间*/

  <bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">

     <property name="cache"><ref local="userCacheBackend"/></property>

  </bean>

 

/*配置daoAuthenticationProvider*/

-1根据用户名获取系统中真实UserDetails 对象的服务类
    
    

 

   <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">

      <property name="userDetailsService"><ref local="jdbcDaoImpl"/></property>

      <property name="userCache"><ref local="userCache"/></property>

   </bean>

 

<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">

     <property name="key"><value>foobar</value></property>

     <property name="userAttribute"><value>anonymousUser,AUTH_ANONYMOUS</value></property>

  </bean>

 

  <bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">

     <property name="key"><value>foobar</value></property>

  </bean>

①注入认证管理器
    
    

 

<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">

      <property name="authenticationManager"><ref bean="authenticationManager"/></property>

      <property name="authenticationFailureUrl"><value>/login.jsp?login_error=1</value></property>

      <property name="defaultTargetUrl"><value>/index.jsp</value></property>

      <property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>

   </bean>

 

<bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">

        <property name="authenticationManager">   <ref bean="authenticationManager"/>            </property>   

         <property name="authenticationEntryPoint">   <ref bean="BasicProcessingFilterEntryPoint"/>   </property>  

     </bean> 

 

<bean id="BasicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">  

         

    </bean>  

 

   <bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">

      <property name="loginFormUrl"><value>/login.jsp</value></property>

      <property name="forceHttps"><value>false</value></property>

   </bean>

 

   <!-- Note the order that entries are placed against the objectDefinitionSource is critical.

        The FilterSecurityInterceptor will work from the top of the list down to the FIRST pattern that matches the request URL.

        Accordingly, you should place MOST SPECIFIC (ie a/b/c/d.*) expressions first, with LEAST SPECIFIC (ie a/.*) expressions last -->

配置完过滤器后,需要对拦截器FilterSecurityInterceptor进行配置

   <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">

      <property name="authenticationManager"><ref bean="authenticationManager"/></property>

      <property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>

      <property name="objectDefinitionSource">

         <value>

               CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

               PATTERN_TYPE_APACHE_ANT

               /**/*.jpg=AUTH_ANONYMOUS,AUTH_USER

               /**/*.gif=AUTH_ANONYMOUS,AUTH_USER

               /**/*.png=AUTH_ANONYMOUS,AUTH_USER

               /login.jsp*=AUTH_ANONYMOUS,AUTH_USER

               /**=AUTH_USER

         </value>

      </property>

   </bean>

 

  <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">

     <property name="allowIfAllAbstainDecisions"><value>false</value></property>

     <property name="decisionVoters">

        <list>

           <ref bean="roleVoter"/>

        </list>

     </property>

  </bean>

  <!-- An access decision voter that reads AUTH_* configuration settings -->

  <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">

    <!-- set that this voter can only used for AUTH_ started roles! -->

    <property name="rolePrefix"><value>AUTH_</value></property>

  </bean>

 

 

FILTER CHAIN

  FilterChainProxy会按顺序来调用这些filter,使这些filter能享用Spring ioc的功能, CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定义了url比较前先转为小写, PATTERN_TYPE_APACHE_ANT定义了使用Apache ant的匹配模式

    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">

        <property name="filterInvocationDefinitionSource">

            <value>

                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

                PATTERN_TYPE_APACHE_ANT

               /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,

basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,

 exceptionTranslationFilter,filterInvocationInterceptor

            </value>

        </property>

    </bean>

基础认证

1) authenticationManager 起到认证管理的作用,它将验证的功能委托给多个Provider,并通过遍历Providers, 以保证获取不同来源的身份认证,若某个Provider能成功确认当前用户的身份,authenticate()方法会返回一个完整的包含用户授权信息的Authentication对象,否则会抛出一个AuthenticationException Acegi提供了不同的AuthenticationProvider的实现,如:         DaoAuthenticationProvider 从数据库中读取用户信息验证身份         AnonymousAuthenticationProvider 匿名用户身份认证         RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证 每个认证者会对自己指定的证明信息进行认证,如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证。

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">

        <property name="providers">

            <list>

                <ref local="daoAuthenticationProvider"/>

                <ref local="anonymousAuthenticationProvider"/>

                <ref local="rememberMeAuthenticationProvider"/>

            </list>

        </property>

</bean>

daoAuthenticationProvider   进行简单的基于数据库的身份验证。 DaoAuthenticationProvider获取数据库中的账号密码并进行匹配,若成功则在通过用户身份的同时返回一个包含授权信息的 Authentication对象,否则身份验证失败,抛出一个AuthenticatiionException

    <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">

        <property name="userDetailsService" ref="jdbcDaoImpl"/>

        <property name="userCache" ref="userCache"/>

        <property name="passwordEncoder" ref="passwordEncoder"/>

   </bean>

 

passwordEncoder   使用加密器对用户输入的明文进行加密。Acegi提供了三种加密器: PlaintextPasswordEncoder—默认,不加密,返回明文. ShaPasswordEncoder—哈希算法(SHA)加密 Md5PasswordEncoder—消息摘要(MD5)加密

<bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>

 

jdbcDaoImpl   用于在数据中获取用户信息。 acegi提供了用户及授权的表结构,但是您也可以自己来实现。通过usersByUsernameQuery这个SQL得到你的(用户ID,密码,状态信息);通过authoritiesByUsernameQuery这个SQL得到你的(用户ID,授权信息)

 

<bean id="jdbcDaoImpl" 

class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">

        

<property name="dataSource" 

ref="dataSource"/>

        <property 

name="usersByUsernameQuery">

            

<value>select loginid,passwd,1 from users where loginid = 

?</value>

        

</property>

        <property 

name="authoritiesByUsernameQuery">

            

<value>select u.loginid,p.name from users u,roles r,permissions 

p,user_role ur,role_permis rp where u.id=ur.user_id and r.id=ur.role_id and 

p.id=rp.permis_id 

and

                

r.id=rp.role_id and p.status='1' and 

u.loginid=?</value>

        

</property>

</bean>

 

userCache &  resourceCache   缓存用户和资源相对应的权限信息。每当请求一个受保护资源时,daoAuthenticationProvider就会被调用以获取用户授权信息。如果每次都从数据库获取的话,那代价很高,对于不常改变的用户和资源信息来说,最好是把相关授权信息缓存起来。userCache提供了两种实现: NullUserCacheEhCacheBasedUserCache, NullUserCache实际上就是不进行任何缓存,EhCacheBasedUserCache是使用Ehcache来实现缓功能。

    <bean id="userCacheBackend" 

class="org.springframework.cache.ehcache.EhCacheFactoryBean">

        

<property name="cacheManager" 

ref="cacheManager"/>

        

<property name="cacheName" value="userCache"/>

    </bean>

    <bean id="userCache" 

class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache" 

autowire="byName">

        <property 

name="cache" ref="userCacheBackend"/>

      

</bean>

    <bean id="resourceCacheBackend" 

class="org.springframework.cache.ehcache.EhCacheFactoryBean">

        

<property name="cacheManager" 

ref="cacheManager"/>

        

<property name="cacheName" value="resourceCache"/>

    </bean>

    <bean id="resourceCache" 

class="org.springside.modules.security.service.acegi.cache.ResourceCache" 

autowire="byName">

        <property 

name="cache" ref="resourceCacheBackend"/>

    </bean>

 

authenticationProcessingFilterEntryPoint   当抛出AccessDeniedException时,将用户重定向到登录界面。属性loginFormUrl配置了一个登录表单的URL, 当需要用户登录时,authenticationProcessingFilterEntryPoint会将用户重定向到该URL

<bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">         <property name="loginFormUrl">             <value>/security/login.jsp</value>         </property>         <property name="forceHttps" value="false"/> </bean>

 

httpSessionContextIntegrationFilter   每次request HttpSessionContextIntegrationFilterSession中获取Authentication对象,在request完后, 又把Authentication对象保存到Session中供下次request使用,filter必须其他Acegi filter前使用,使之能跨越多个请求。

<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"></bean>

    <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">

        <property name="allowIfAllAbstainDecisions" value="false"/>

        <property name="decisionVoters">

            <list>

                <ref bean="roleVoter"/>

            </list>

        </property>

</bean>

 

 

httpRequestAccessDecisionManager   经过投票机制来决定是否可以访问某一 资源(URL或方法)allowIfAllAbstainDecisionsfalse时如果有一个或以上的decisionVoters投票通过, 则授权通过。可选的决策机制有ConsensusBasedUnanimousBased

    <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">

        <property name="allowIfAllAbstainDecisions" value="false"/>

        <property name="decisionVoters">

            <list>

                <ref bean="roleVoter"/>

            </list>

        </property>

    </bean>

 

roleVoter    必须是以rolePrefix设定的value开头的权限才能进行投票,AUTH_ , ROLE_

    <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">

        <property name="rolePrefix" value="AUTH_"/>

   </bean>

 

exceptionTranslationFilter   异常转换过滤器,主要是处理AccessDeniedExceptionAuthenticationException,将给每个异常找到合适的"去向

   <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">

        <property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/>

    </bean>

 

 

authenticationProcessingFilter   和servlet spec差不多,处理登陆请求.当身份验证成功时,AuthenticationProcessingFilter会在会话中放置一个Authentication对象,并且重定向到登录成功页面          authenticationFailureUrl定义登陆失败时转向的页面          defaultTargetUrl定义登陆成功时转向的页面          filterProcessesUrl定义登陆请求的页面          rememberMeServices用于在验证成功后添加cookie信息

    <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">

        <property name="authenticationManager" ref="authenticationManager"/>

        <property name="authenticationFailureUrl">

            <value>/security/login.jsp?login_error=1</value>

        </property>

        <property name="defaultTargetUrl">

            <value>/admin/index.jsp</value>

        </property>

        <property name="filterProcessesUrl">

            <value>/j_acegi_security_check</value>

        </property>

        <property name="rememberMeServices" ref="rememberMeServices"/>

    </bean>

 

filterInvocationInterceptor   在执行转向url前检查 objectDefinitionSource中设定的用户权限信息。首先,objectDefinitionSource中定义了访问URL需要的属性 信息(这里的属性信息仅仅是标志,告诉accessDecisionManager要用哪些voter来投票)。然后, authenticationManager掉用自己的provider来对用户的认证信息进行校验。最后,有投票者根据用户持有认证和访问url需要的 属性,调用自己的voter来投票,决定是否允许访问。

    <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">

        <property name="authenticationManager" ref="authenticationManager"/>

        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>

        <property name="objectDefinitionSource" ref="filterDefinitionSource"/>

    </bean>

 

filterDefinitionSource   自定义DBFilterInvocationDefinitionSource从数据库和cache中读取保护资源及其需要的访问权限信息 

<bean id="filterDefinitionSource" class="org.springside.modules.security.service.acegi.DBFilterInvocationDefinitionSource">         <property name="convertUrlToLowercaseBeforeComparison" value="true"/>         <property name="useAntPath" value="true"/>         <property name="acegiCacheManager" ref="acegiCacheManager"/> </bean>

 

name="cache" ref="resourceCacheBackend"/>     </bean>

 

 

程序

组成

1、  数据库访问的接口(IContactDao.javaContactDao.java

2、  代理访问数据类,在配置中是拦截这个类的方法(IContactManager.javaContactManager.java

3、  数据库中定义的需要控制的资源,对应得访问类(DataSourceMethodDefinitionSourceEditor.java

4、  实体对象类(Contact.java

5、  控制数据权限需要得到用户身份信息的类(AppropriatingFundsVoter.java

结构:

 

SecurityContextHolder是框架级的容器,它保存着和所有用户关联SecurityContext实例, SecurityContext承载着用户(也称认证主体)的身份信息的权限信息, AuthenticationManagerAccessDecisionManager将据此进行安全访问控制。

 

SecurityContext的认证主体安全信息在一个HTTP请求线程的多个调用之间是共享的(通过ThreadLocal),但它不能在多个请求之 间保持共享。为了解决这个问题,Acegi将认证主体安全信息缓存于HttpSession中,当用户请求一个受限的资源时,Acegi通过 HttpSessionContextIntegrationFilter将认证主体信息从HttpSession中加载到 SecurityContext实例中,认证主体关联的SecurityContext实例保存在Acegi容器级的 SecurityContextHolder里。当请求结束之后,HttpSessionContextIntegrationFilter执行相反的操 作,将SecurityContext中的认证主体安全信息重新转存到HttpSession中,然后从SecurityContextHolder中清 除对应的SecurityContext实例。通过HttpSession转存机制,用户的安全信息就可以在多个HTTP请求间共享,同时保证 SecurityContextHolder中仅保存当前有用的用户安全信息,其整体过程如图 2所示:

 

当用户请求一个受限的资源时,AuthenticationManager首先开始工作,它象一个安检入口,对用户身份进行核查,用户必须提供身份认证的 凭证(一般是用户名/密码)。在进行身份认证时,AuthenticationManager将身份认证的工作委托给多个 AuthenticationProvider。因为在具体的系统中,用户身份可能存储在不同的用户信息安全系统中(如数据库、CA中心、LDAP服务 器),不同用户信息安全系统需要不同的AuthenticationProvider执行诸如用户信息查询、用户身份判断、用户授权信息获取等工作。只要 有一个AuthenticationProvider可以识别用户的身份,AuthenticationManager就通过用户身份认证,并将用户的授 权信息放入到SecurityContext中。    当用户通过身份认证后,试图访问某个受限的程序资源时,AccessDecisionManager开始工作。 AccessDecisionManager采用民主决策机制判断用户是否有权访问目标程序资源,它包含了多个AccessDecisionVoter 在访问决策时每个AccessDecisionVoter都拥有投票权,AccessDecisionManager统计投票结果,并按照某种决策方式根 据这些投票结果决定最终是否向用户开放受限资源的访问。

 

 

Usedetails

UserDetails接口,它代表一个应用系统的用户,该接口定义了用户安全相关的信息,如用户名/密码,用户是否有效等信息,你可以根据以下接口方法进行相关信息的获取:     String getUsername():获取用户名;       String getPassword():获取密码;       boolean isAccountNonExpired():用户帐号是否过期;       boolean isAccountNonLocked():用户帐号是否锁定;       boolean isCredentialsNonExpired():用户的凭证是否过期;       boolean isEnabled():用户是否处于激活状态。     当以上任何一个判断用户状态的方法都返回false时,用户凭证就被视为无效。     UserDetails还定义了获取用户权限信息的方法:GrantedAuthority[] getAuthorities()GrantedAuthority代表用户权限信息,它定义了一个获取权限描述信息(以字符串表示,如 PRIV_COMMON)的方法:String getAuthority()

 

UserDetails可能从数据库、LDAP等用户信息资源中返回,这要求有一种机制来完成这项工作,UserDetailsService正是充当这 一角色的接口。UserDetailsService接口很简单,仅有一个方法:UserDetails loadUserByUsername(String username) ,这个方法通过用户名获取整个UserDetails对象。 Authentication代表一个和应用程序交互的待认证用户,Acegi从类似于登录页面、Cookie等处获取待认证的用户信息(一般是用户名密码)自动构造Authentication实例。

 

Authentication可以通过Object getPrincipal()获取一个代表用户的对象,这个对象一般可以转换为UserDetails,从中可以取得用户名/密码等信息。在 AuthenticationAuthenticationManager认证之前,没有任何权限的信息。在通过认证之后,Acegi通过 UserDetails将用户对应的权限信息加载到Authentication中。Authentication拥有一个 GrantedAuthority[] getAuthorities()方法,通过该方法可以得到用户对应的权限信息。     AuthenticationUserDetails很容易被混淆,因为两者都有用户名/密码及权限的信息,接口方法也很类似。其实 AuthenticationAcegi进行安全访问控制真正使用的用户安全信息的对象,它拥有两个状态:未认证和已认证。UserDetails是代 表一个从用户安全信息源(数据库、LDAP服务器、CA中心)返回的真正用户,Acegi需要将未认证的Authentication和代表真实用户的 UserDetails进行匹配比较,通过匹配比较(简单的情况下是用户名/密码是否一致)后,AcegiUserDetails中的其它安全信息(如 权限、ACL等)拷贝到Authentication中。这样,Acegi安全控制组件在后续的安全访问控制中只和Authentication进行交 互。

由于Acegi对程序资源进行访问安全控制时,一定要事先获取和请求用户对应的AuthenticationAcegi框架必须为Authentication提供一个寓所,以便在需要时直接从寓所把它请出来,作为各种安全管理器决策的依据。

SecurityContextHolder就是Authentication容身的寓所,你可以通过 SecurityContextHolder.getContext().getAuthenication()代码获取Authentication 细心观察一下这句代码,你会发现在SecurityContextHolderAuthentication之间存在一个getContext() 介,这个方法返回SecurityContext对象。SecurityContext这个半路杀出来的程咬金有什么特殊的用途呢?我们知道 Authentication是用户安全相关的信息,请求线程其它信息(如登录验证码等)则放置在SecurityContext中,构成了一个完整的安 全信息上下文。SecurityContext接口提供了获取和设置Authentication的方法:  Authentication getAuthentication()l  void setAuthentication(Authentication authentication)l

 

SecurityContextHolderAcegi框架级的对象,它在内部通过ThreadLocal为请求线程提供线程绑定的 SecurityContext对象。这样,任何参与当前请求线程的Acegi安全管理组件、业务服务对象等都可以直接通过 SecurityContextHolder.getContext()获取线程绑定的SecurityContext,避免通过方法入参的方式获取用户 相关的SecurityContext     线程绑定模式对于大多数应用来说是适合的,但是应用本身会创建其它的线程,那么只有主线程可以获得线程绑定SecurityContext,而主线程衍生 出的新线程则无法得到线程绑定的SecurityContextAcegi考虑到了这些不同应用情况,提供了三种绑定SecurityContext 模式:  SecurityContextHolder.MODE_THREADLOCALSecurityContext绑定到主线程,这是默认的模式;l  SecurityContextHolder.MODE_GLOBALSecurityContext绑定到JVM中,所有线程都使用同一个SecurityContextl  SecurityContextHolder.MODE_INHERITABLETHREADLOCAL::SecurityContext绑定到主线程及由主线程衍生的线程中。l     你可以通过SecurityContextHolder.setStrategyName(String strategyName)方法指定SecurityContext的绑定模式。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值