`
pxchen
  • 浏览: 90892 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

spring-scurity

阅读更多
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<!-- ======================== FILTER CHAIN =======================
FilterChainProxy will transfer these filters by order to make them use the Ioc of spring.
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON define that convert url to lowrcase befor comparing
PATTERN_TYPE_APACHE_ANT define that use the model of apache ant.
-->

<!-- 目标委托的bean 下面的value就是多个过滤器的组合成过滤链 这个bean是web.xml的
filterChainProx的委托目标。
注意顺序.
-->
<bean id="filterChainProxy"
   class="org.acegisecurity.util.FilterChainProxy">
   <property name="filterInvocationDefinitionSource">
    <value>
     CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
     PATTERN_TYPE_APACHE_ANT
     /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
    </value>
    <!-- Put channelProcessingFilter before securityContextHolderAwareRequestFilter to turn on SSL switching -->
    <!-- It's off by default b/c Canoo WebTest doesn't support SSL out-of-the-box -->
   </property>
</bean>
<!-- 过滤器链中的过滤器 通过HttpSession转存SecurityContext的过滤器.如果用户还为通过认证,httpSessionContextIntegrationFilter
在HttpSession中找不到对应的SecurityContext这时authenticationProcessingFilter将启动正常的认证流程,反之,如果通过认证,
SecurityContext将直接从HttpSession中取出。-->
<bean id="httpSessionContextIntegrationFilter"
   class="org.acegisecurity.context.HttpSessionContextIntegrationFilter" />

<!-- SecurityContext 保存在HttpSession中,当用户退出系统的时候必须清楚,否则其会一直保存于HttpSession中,直到session过期才被清除
通常推出系统会记录日志,将登录信息保存到cookie里面等。LogoutFilter接口 -->
<bean id="logoutFilter"
   class="org.acegisecurity.ui.logout.LogoutFilter">
   <constructor-arg value="/login.jsp" /><!-- 退出系统时候后转向的URL-->
   <!-- URL redirected to after logout -->
   <constructor-arg>
    <list>
   
     <ref bean="rememberMeServices" />
   
     <!-- SecurityContextLogoutHandler是LogoutFilter的一个实现类,是将SecurityContext从HttpSession中删除
     另一个是:TokenBasedRememberMeServices,是将Authentication中的用户名和密码保存到客户端的cookie里面,以便下次
     用户访问的时候直接通过cookie里取 -->
     <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
    </list>
   </constructor-arg>
   <property name="filterProcessesUrl" value="/logout.jsp" /><!-- 指定推出系统的URL请求 -->
</bean>
<!-- 使用认证处理过滤器处理匹配的url. -->
<bean id="authenticationProcessingFilter"
   class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
   <!--其实AuthenticationProcessingFilter只是从页面获取用户信息,根据认证结果完成页面转向,处理认证的过程是需要authenticationManager
   在后台完成,authenticationManager是认证管理器 -->
   <property name="authenticationManager" ref="authenticationManager" />
 
   <!-- 认证失败时候转向的页面 -->
   <property name="authenticationFailureUrl" value="/login.jsp?error=true" />
 
   <property name="defaultTargetUrl" value="/" />
 
   <!-- 与login.jsp中form的action是一样的,当该表单提交后,authenticationProcessingFilter将从请求中提取出j_username,j_paassword的值
   两者组成了代表请求认证的用户信息,acegi将这个信息构造成Authentication实例,并且封装成SecurityContext放入到SecurityContextHolder中
   然后启动用户身份认证的流程,如果失败,会/login.jsp?error=true,成功的话.... -->
   <property name="filterProcessesUrl" value="/j_security_check" />
 
   <!-- 添加rememberMe,在处理用户登录页面提交的用户认证信息时候,将用户名和密码通过response的方式记录到客户端cookie中
      当authenticationProcessingFilter 完成用户认证的时候,如果认证成功,调用 rememberMeServices的loginSuccess()方法
      该方法将用户名和密码按以某种方式进行编码,然后再写入到cookie里面 -->
   <property name="rememberMeServices" ref="rememberMeServices" />
</bean>

<bean id="securityContextHolderAwareRequestFilter"
   class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" />

<!-- 自动登录功能,如果保存到cookie里面5天内,再次自动登录。必须有一个过滤器能够自动调用RememberMeServices#autoLogin()方法
    这个需要通过rememberMeProcessingFilter过滤器来完成。 -->
<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
   <property name="authenticationManager" ref="authenticationManager" />
   <property name="rememberMeServices" ref="rememberMeServices" />
</bean>

<!-- 匿名用户处理过滤器 添加anonymousProcessingFilter到过滤器链中AnonymousProcessingFilter和AnonymousAuthenticationProvider
都拥有一个key属性,key是建立两者联系的桥梁,要想等这样,后者就可以通过key访问到前者创建的AnonymousAuthenticationToken -->
<bean id="anonymousProcessingFilter"
   class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
   <property name="key" value="anonymous" />
   <!--匿名用户的属性,其中第一项anonymous表示用户密码,第二项ROLE_ANONYMOUS表示对应权限,以逗号分开可以添加多个权限 -->
   <property name="userAttribute" value="anonymous,ROLE_ANONYMOUS" />
</bean>

<!-- 异常转换过滤器: 能够扑捉Acegi抛出的权限访问异常,并导向合适相应页面
注意:ExceptionTranslationFilter必须位于FilterSecurityInterceptor之前
-->
<bean id="exceptionTranslationFilter"
   class="org.acegisecurity.ui.ExceptionTranslationFilter">
   <!-- 通过AuthenticationProcessingFilterEntryPoint定义用户登录页面的地址,在抛出AuthenticationException异常时,
       请求到login.jsp页面 -->
   <property name="authenticationEntryPoint">
    <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
     <property name="loginFormUrl" value="/login.jsp" />
     <property name="forceHttps" value="false" />
    </bean>
   </property>
</bean>

<!-- start:overrided by bguo since in our project, the authority data is from DB -->
<!--
   <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
   <property name="authenticationManager" ref="authenticationManager"/>
   <property name="accessDecisionManager" ref="accessDecisionManager"/>
   <property name="objectDefinitionSource" >
   <value>
   PATTERN_TYPE_APACHE_ANT
   /clickstreams.jsp*=admin
   /flushCache.*=admin
   /mainMenu.action*=ROLE_ANONYMOUS,admin,user
   /passwordHint.action*=ROLE_ANONYMOUS,admin,user
   /reload.*=admin
   /signup.action*=ROLE_ANONYMOUS,admin,user
   /users.action*=admin
   /**/*.action*=admin,user
   </value>
   </property>
   </bean>
-->

<!-- URL 资源访问拦截器,添加到拦截器链中,改拦截器将对所有URL请求进行处理,拦截流程如下:
1:判断用户是否已经通过认证,如NO,调用身份认证管理器进行处理,这意味着请求将重定向到登录页面
2:如果通过认证,调用访问决策管理器判断用户是否有权限访问目标 URL资源。
3:访问管理器将组织投票者进行投票,并根据投票结果给出是否有权限访问。
4:如果无权限,则抛出Expception,否则开发URL访问
-->
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
   <!-- 有上面注释可以得出:FilterSecurityInterceptor要能正常工作,必须得到身份认证管理器和访问决策管理器两者配合 -->
   <property name="authenticationManager" ref="authenticationManager" />
   <property name="accessDecisionManager" ref="accessDecisionManager" />
 
   <!-- Authentication#getAuthorities()方法返回的GrantedAuthority[]代表用户的权限信息,但在判断用户是否拥有访问目标URL
   权限时候,必须将URL资源事先转换为投票者可以识别的权限信息。改项目通过自己的方法 找出权限信息 -->
   <property name="objectDefinitionSource" ref="gbUrlFilterDefinitionSource">
   </property>
</bean>
<!-- 上面调用该方法 -->
<bean id="gbUrlFilterDefinitionSource"
   class="com.abeam.nasa.service.impl.common.GbUrlDefinitionSource">
   <property name="functionDao" ref="functionDao" />
   <property name="functionsByUserCache" ref="functionsUserCache" />
   <property name="authorityFunctionCache" ref="authorityFunctionCache" />
</bean>

<!-- end:overrided by bguo since in our project, the authority data is from DB -->

<!-- HTTP请求访问决策管理器 -->
<bean id="accessDecisionManager"
   class="org.acegisecurity.vote.AffirmativeBased">
 
   <!-- 是否所有投票者弃权 即 为同意 -->
   <property name="allowIfAllAbstainDecisions" value="false" />
 
   <!-- 投票者列表 -->
   <property name="decisionVoters">
    <list>
     <!-- 投票者 -->
     <bean class="org.acegisecurity.vote.RoleVoter">
      <!-- 对应的权限前缀(只对前缀匹配的权限投票) -->
      <property name="rolePrefix" value="" />
     </bean>
    </list>
   </property>
</bean>

<!-- RememberMeServices接口实现类TokenBasedRememberMeServices(基于凭证 即:用户名和密码 的remember—me实现类。)
      改实现类和logoutFilter的那个TokenBasedRememberMeServices名字一样,但意思相同 可能都实现了。
      本项目自己实现了RememberMeServices 并且继承了TokenBasedRememberMeServices实现类。扩展了
      -->
<bean id="rememberMeServices"
   class="com.abeam.nasa.security.NasaTokenBasedRememberMeServices">
   <property name="userDetailsService" ref="userDao" /> <!-- 要引用的Dao -->
   <property name="key" value="appfuseRocks" /><!-- Cookie 中的键值,通过key值,可以有效防止整个加密串被黑客改动,因为key值在服务器端 -->
   <property name="parameter" value="rememberMe" />
   <!-- 也可以添加cookie的有效时间,单位是秒。
   <property name="tokenValiditySeconds" value="432000"/>
   -->
</bean>

<!--authenticationManager有两个实现类:MockAuthenticationManager和ProviderManager
MockAuthenticationManager用于开发测试环境,它将所有待认证用户标志为有效用户
ProviderManager:将用户的省份认证工作委托给多个提供者来完成。本项目用地是ProviderManager -->
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
   <property name="providers">
    <list>
    <!-- 这里只是加上了3个认证提供者,还有一些其他的.... -->
     <!-- 使用基于Dao的认证,转下面的引用 -->
     <ref local="daoAuthenticationProvider" />
   
     <!-- 需要将anonymousAuthenticationProvider添加到authenticationManager的认证提供者列表中,以便
        AnonymousAuthenticationToken能够通过认证管理器的认证 -->
     <ref local="anonymousAuthenticationProvider" />
   
     <ref local="rememberMeAuthenticationProvider" />
    </list>
   </property>
</bean>
<!-- DaoAuthenticationProvider 首先从SecurityContextHolder的Authentication中得到待认证的用户名,并根据该用户名获取保存在
数据库或其他媒介中真正的系统用户UserDetail对象,紧接着比较Authentication和UserDetails的匹配关系(如看密码是否相同,校验码等),如不匹配失败
本项目用到了自己的认证方式,NasaDaoAuthenticationProvider是自己写的实现UserDetailsServics.没有用到acegi里面的JdbcDaoImpl
和InMemoryDaoImpl。如下:
<bean id="daoAuthenticationProvider"
   class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
   <property name="userDetailsService" ref="userDetailsService" />
   <property name="passwordEncoder" ref="passwordEncoder" />
</bean>
1:这个方式是基于数据库存储的用户信息获取,JdbcDaoImpl是acegi里面UserDetailsServics的实现类。
<bean id="userDetailsService"
   class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
   <property name="dataSource" ref="dataSource" /> //数据源.
   <property name="usersByUsernameQuery">
    <value>
     SELECT username,password,1 FROM t_user WHERE status='1'
     AND username = ?            //这里的value就是根据用户名来查的值的sql
    </value>
   </property>
   <property name="authoritiesByUsernameQuery">
    <value>
     SELECT u.username,p.priv_name FROM t_user u,t_user_priv
     p WHERE u.user_id =p.user_id AND u.username = ?   //根据用户名来查询用户权限记录的sql
    </value>
   </property>
</bean>
2:这个方式是基于缓存中的用户信息获取,InMemoryDaoImpl是acegi里面对UserDetailsServics接口的实现类。从内存中获取信息
<bean id="userDetailsService"
   class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">

<property name="userMap" > //user权限集合
<value> //用户信息
     join=join,PRIV_COMMON,PRIV_1
     tom=tom,PRIV_COMMON,PRIV_1,PRIV_2
     peter=peter,disable,PRIV_COMMON,PRIV_1
   </value>
</property>

或者如下写入properties
   <property name="userProperties" > //user权限集合
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
   <property name="location" value="/WEB-INF/users.properties"/>
</bean>
</property>

</bean>
   -->
<bean id="daoAuthenticationProvider"
   class="com.abeam.nasa.security.NasaDaoAuthenticationProvider">
   <property name="userDetailsService" ref="userDao" />
   <!-- 加密方式,将页面传来的明文加密然后对比数据库中的 -->
   <property name="passwordEncoder" ref="passwordEncoder" />
</bean>
<!-- replaced by bguo for LDAP configure start
<bean id="daoAuthenticationProvider"
   class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
   <property name="userDetailsService" ref="userDao" />
   <property name="passwordEncoder" ref="passwordEncoder" />
</bean>
end -->

    <!-- 该key与anonymousProcessingFilter的key值要相等-->
<bean id="anonymousAuthenticationProvider"
   class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
   <property name="key" value="anonymous" />
</bean>

<bean id="rememberMeAuthenticationProvider"
   class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
   <property name="key" value="appfuseRocks" />
</bean>

<!-- This bean definition must be available to ApplicationContext.getBean() so StartupListener
   can look for it and detect if password encryption is turned on or not -->
<bean id="passwordEncoder"
   class="org.acegisecurity.providers.encoding.ShaPasswordEncoder" />

<!-- This bean is optional; it isn't used by any other bean as it only listens and logs -->
<bean id="loggerListener"
   class="org.acegisecurity.event.authentication.LoggerListener" />

<!-- Apply method-level interceptor to userManager bean -->
<!-- start:removed by bguo since in our project, the method is not the control object -->
<!--
   <aop:config>
   <aop:advisor id="managerSecurity" advice-ref="methodSecurityInterceptor" pointcut="execution(* com.abeam.nasa.service.UserManager.*(..))"/>
   </aop:config>
 
   <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
   <property name="authenticationManager" ref="authenticationManager"/>
   <property name="accessDecisionManager" ref="accessDecisionManager"/>
   <property name="objectDefinitionSource">
   <value>
   com.abeam.nasa.service.UserManager.getUsers=admin
   com.abeam.nasa.service.UserManager.removeUser=admin
   </value>
   </property>
   </bean>
-->
<!-- end:removed by bguo since in our project, the method is not the control object -->

<!-- SSL Switching: to use this, configure it in the filterChainProxy bean -->
<!-- 安全通道过滤器:通过channelProcessiongFilter 对所有URL资源访问进行过滤,当发现访问目标URL所使用的传输协议不符合要求时候,就执行
切换传输协议的操作,该过滤器必须要在过滤器链的最前面。 -->
<bean id="channelProcessingFilter"
   class="org.acegisecurity.securechannel.ChannelProcessingFilter">
   <property name="channelDecisionManager"
    ref="channelDecisionManager" />
   <property name="filterInvocationDefinitionSource">
    <value>
     PATTERN_TYPE_APACHE_ANT
     /admin/**=REQUIRES_SECURE_CHANNEL
     /login*=REQUIRES_SECURE_CHANNEL
     /j_security_check*=REQUIRES_SECURE_CHANNEL
     /editProfile.action*=REQUIRES_SECURE_CHANNEL
     /signup.action*=REQUIRES_SECURE_CHANNEL
     /saveUser.action*=REQUIRES_SECURE_CHANNEL
     /**=REQUIRES_INSECURE_CHANNEL
    </value>
   </property>
</bean>
<!-- ChannelProcessingFilter 过滤器在拦截URL访问的请求后,根据ChannelDesisionManager判断目标URL需要使用的传输协议和当前使用的
协议是否一致,如果不一致,ChannelDecisionManager通过channelProecssors属性定义的通道处理器进行切换 -->
<bean id="channelDecisionManager"
   class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl">
   <property name="channelProcessors">
    <list>
     <bean
      class="org.acegisecurity.securechannel.SecureChannelProcessor" /><!-- 安全通道处理器 -->
     <bean
      class="org.acegisecurity.securechannel.InsecureChannelProcessor" /><!-- 非安全通道处理器 -->
    </list>
   </property>
</bean>
</beans>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics