spring_security-安全框架

来源:互联网 发布:linux用户权限同组 编辑:程序博客网 时间:2024/05/22 10:39

本文转自:http://itblood.com/spring-security-security-framework.html

安全常识:
 
Acegi介绍:
 以声明式方式为基于Spring的web应用添加认证和授权控制
 
 
Acegi体系结构:
     拦截器
认证管理器、访问控制管理器。

认证:
  拦截器:
   authenticationProcessingFilter 
  认证管理器:
   AuthenticationManager:
    使用多个提供者实施认证:
     如:DaoAuthenticationProvider
    提供者使用UserDetailsService获得认证用户信息。
URL资源的授权:
  拦截器:
   FilterSecurityInterceptor:
    (1)使用认证管理器判断用户是否通过身份认证。
    (2)调用访问控制器判断用户可否访问URL资源
    (3)访问控制管理器投票
    (4)无权访问,抛出异常,否则开放。
    
  认证管理器:同上
  访问控制管理器:
   组织投票者投票,投票者依据对象定义源中定义的安全对象信息来投票。
   accessDecisionManager有三类

业务方法的访问授权:
  拦截器:
   MethodSecurityInterceptor:
   
其它相关过滤器:
  ExceptionTranslationFilter:异常转换过滤器
  异常转换过滤器必须放在FilterSecurityInterceptor之前。
  发现异常,先判断用户是否已经登录,未登录,导向登录;已登录,导向出错页面。
  HttpSessionContextIntegrationFilter:
   request处理前,该过滤器从Session中获取Authentication对象,在request完后
   又把Authentication对象保存到Session中供下次request使用,此filter必须于其他Acegi Filter前使用。
   使得多个请求可以共享Authentication对象
  LogoutFilter:
   退出系统的善后工作,主要是将安全上下文从Session中删除。
  anonymousProcessingFilter: 
   未登录用户可以访问的资源,使用用户可以登录,访问首页等不需要保护的资源。 
   
编程:    
一、准备工作:
 
 添加acegi的包

二、认证
  1、在web.xml中,配置如下信息:
    <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <filter>
     <filter-name>AcegiFilterChainProxy</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>
    <filter-mapping>
     <filter-name>AcegiFilterChainProxy</filter-name>
     <url-pattern>/*</url-pattern>
    </filter-mapping>
    <listener>
     <listener-class>
      org.springframework.web.context.ContextLoaderListener
     </listener-class>
    </listener>
   说明:
    FilterToBeanProxy:代理Acegi的过滤器
    FilterChainProxy:将多个过滤组成一个过滤器链
      
  2、添加登录页面:
    <form name="form1" method="post" action="<c:url value="/j_acegi_security_check"/>">
     用户名:<input type="text" name="j_username"/><br/>
     密 码:<input type="password" name="j_password"/><br/>
     <input type="submit" value="登录"/>
    </form>
  3、在Spring配置文件中,添加配置信息:
     <bean id="dataSource"
      class="org.apache.commons.dbcp.BasicDataSource"
      destroy-method="close">
      <property name="driverClassName">
       <value>com.mysql.jdbc.Driver</value>
      </property>
      <property name="url">
       <value>jdbc:mysql://localhost:3306/tarena</value>
      </property>
      <property name="username">
       <value>root</value>
      </property>
      <property name="password">
       <value>1234</value>
      </property>
     </bean>
     
     <bean id="filterChainProxy"
      class="org.acegisecurity.util.FilterChainProxy">
      <property name="filterInvocationDefinitionSource">
       <value>
        CONVERT_URL_TO_UPPERCASE_BEFORE_COMPARISON
        PATTERN_TYPE_APACHE_ANT
        /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter
       </value>
      </property>
     </bean>
     
     <!--
      1)request处理前,该过滤器从Session中获取Authentication对象,在request完后
      又把Authentication对象保存到Session中供下次request使用
      2)此filter必须于其他Acegi Filter前使用
     -->
     <bean id="httpSessionContextIntegrationFilter"
      class="org.acegisecurity.context.HttpSessionContextIntegrationFilter" />
      
     <bean id="authenticationProcessingFilter"
      class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
      <property name="authenticationManager"
       ref="authenticationManager" />
      <property name="authenticationFailureUrl"
       value="/index.jsp?login_error=1" />
      <property name="defaultTargetUrl" value="/main.jsp" />
      <!-- 过滤器处理的url -->
      <property name="filterProcessesUrl"
       value="/j_acegi_security_check" />
     </bean>
 
     <bean id="authenticationManager"
      class="org.acegisecurity.providers.ProviderManager">
      <property name="providers">
       <list>
        <ref local="daoAuthenticationProvider" />
        </list>
      </property>
     </bean>
 
    <bean id="daoAuthenticationProvider"
     class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
     <property name="userDetailsService" ref="userDetailsService" />
    </bean>
    
   <bean id="userDetailsService"
    class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
    <property name="dataSource" ref="dataSource" />
    <property name="usersByUsernameQuery">
     <value>
      SELECT username,password,status FROM t_user WHERE status='1'
      AND username = ?
     </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 = ?
     </value>
    </property>
   </bean>
 
   <bean id="logoutFilter"
    class="org.acegisecurity.ui.logout.LogoutFilter">
    <constructor-arg value="/index.jsp" />
    <constructor-arg>
     <list>
      <bean
       class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
     </list>
    </constructor-arg>
    <property name="filterProcessesUrl" value="/j_acegi_logout" />
   </bean> 
 
  <bean id="orderProcessService" class="service.OrderProcessService" /> 

 4、建表,并插入记录
   

 备注:
   org.acegisecurity.util.FilterToBeanProxy:代理Acegi的过滤器
   org.acegisecurity.util.FilterChainProxy:将多个过滤组成一个过滤器链
   通过filterInvocationDefinitionSource属性定义多个相互链接的过滤器
   其属性定义由两部分组成:
    指令信息
    具体的资源定义信息
  
  
  httpSessionContextIntegrationFilter:
    每次request前 HttpSessionContextIntegrationFilter从Session中获取Authentication对象,在request完后
    又把Authentication对象保存到Session中供下次request使用,此filter必须其他Acegi filter前使用
    
  org.acegisecurity.ui.webapp.AuthenticationProcessingFilter:
    从请求中提取j_username和j_password参数的值,并使用这个信息构造Authentication实例,并封装成SecurityContext放入到
    SecurityContextHolder中,然后启动身份认证的流程。
    
    
  org.acegisecurity.providers.ProviderManager
    将用户身份认证工作委托给多个提供者来完成
    
  补充:
  添加密码控制:

   step1:
    修改daoAuthenticationProvider的配置,添加
     <property name="passwordEncoder">
      <bean class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
     </property>
     <property name="saltSource">
      <bean class="org.acegisecurity.providers.dao.salt.SystemWideSaltSource">
       <property name="systemWideSalt" value="tarena"/>
      </bean>
     </property>
     注意,密码盐的值应该和数据库中加密密码时采用的密码盐一致。
   
   step2:
    对数据库中的密码加密
    加密方式可用org.acegisecurity.providers.encoding.Md5PasswordEncoder工具类:
    比如:String encrtStr = mp.encodePassword("sdd", "tarena");

三、授权
 URL资源的访问授权
  1、修改spring配置文件
   (1)修改filterChainProxy,增加
    anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
   (2)添加anonymousProcessingFilter配置
     <bean id="anonymousProcessingFilter"
      class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
      <property name="key" value="anonymousUser" />
      <property name="userAttribute"
       value="ANONYMOUSUSER,PRIV_ANONYMOUS" />
     </bean>
     <bean id="anonymousAuthenticationProvider"
      class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
      <property name="key" value="anonymousUser" />
     </bean>
   (3)修改authenticationManager增加认证提供者
     <ref local="anonymousAuthenticationProvider" />
   (4)添加filterSecurityInterceptor配置
      <bean id="filterSecurityInterceptor"
       class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
       <property name="authenticationManager"
        ref="authenticationManager" />
       <property name="accessDecisionManager"
        ref="accessDecisionManager" />
       <property name="objectDefinitionSource">
        <value><![CDATA[
         CONVERT_URL_TO_UPPERCASE_BEFORE_COMPARISON
         PATTERN_TYPE_APACHE_ANT
         /processOrder.jsp=PRIV_1
         /viewStock.jsp=PRIV_2
         /**=PRIV_ANONYMOUS,PRIV_COMMON
         ]]>
        </value>
       </property>
      </bean>
      <!--
       经过投票机制来决定是否可以访问某一资源(URL或方法)
       allowIfAllAbstainDecisions属性值是false,意思是如果所有的授权投票是都是弃权,则通不过授权检查
      -->
      <bean id="accessDecisionManager"
       class="org.acegisecurity.vote.AffirmativeBased">
       <property name="allowIfAllAbstainDecisions" value="true" />
       <property name="decisionVoters">
        <list>
         <ref bean="roleVoter" />
        </list>
       </property>
      </bean>
      <!--必须是以rolePrefix设定的value开头的才会进行投票,否则为弃权-->
      <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
       <property name="rolePrefix" value="PRIV_" />
      </bean>
    (5)添加异常转换过滤器
      <bean id="exceptionTranslationFilter"
      class="org.acegisecurity.ui.ExceptionTranslationFilter">
      <property name="authenticationEntryPoint">
       <ref local="authenticationProcessingFilterEntryPoint" />
      </property>
      <property name="accessDeniedHandler">
       <bean
        class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
        <property name="errorPage" value="/error.jsp" />
       </bean>
      </property>
     </bean>
     <bean id="authenticationProcessingFilterEntryPoint"
      class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
      <property name="loginFormUrl">
       <value>/index.jsp</value>
      </property>
     </bean>
    
 业务方法的访问授权
  1、修改spring配置文件
   (1)添加
      <bean id="methodSecurityInterceptor"
       class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
       <property name="authenticationManager" ref="authenticationManager" />
       <property name="accessDecisionManager" ref="accessDecisionManager" />
       <property name="objectDefinitionSource" ref="objectDefinitionSource" />
      </bean>
      <bean id="objectDefinitionSource"
       class="org.acegisecurity.intercept.method.MethodDefinitionAttributes">
       <property name="attributes">
        <bean class="org.acegisecurity.annotation.SecurityAnnotationAttributes" />
       </property>
      </bean>
     
      <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="interceptorNames">
              <list>
                 <value>methodSecurityInterceptor</value>
              </list>
          </property>
          <property name="beanNames">
              <list>
                  <value>orderProcessService</value>
              </list>
          </property>
     </bean>

   2、在业务方法前,添加权限控制标注
     @Secured({"PRIV_2"})


表示层的相关标签:
 <authz:authorize>标签能够根据当前用户是否拥有恰当权限来决定显示或隐藏Web页面的内容
 1、JSP页面引入
 <%@ taglib prefix="authz" uri="http://acegisecurity.org/authz" %>
 2、对需要控制输出的内容,添加
 <authz:authentication operation="username"/>
 <authz:authorize ifAllGranted="PRIV_2">

  ifAllGranted——是一个由逗号分隔的权限列表,用户必须拥有所有列出的权限才列出;
  ifAnyGranted——是一个由逗号分隔的权限列表,用户必须至少拥有其中的一个才列出;
  ifNotGranted——是一个由逗号分隔的权限列表,用户必须不拥有其中的任何一个才列出。
  
添加安全通道功能
 1、配置jboss服务器,启动HTTPS
 step1:
  生成keystore:
  采用jdk的keytool命令即可
  keytool -genkey -alias tomcat -keyalg RSA -keystore d:/tomcat.keystore
 step2:
  将tomcat.keystore复制到server/default/conf下
 step3:
  修改server/default/deploy/jboss-web.deployer/server.xml
  <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false"
               keystoreFile="${jboss.server.home.dir}/conf/tomcat.keystore"  
        keystorePass="windows" sslProtocol="TLS" />
  注意,此处的windows是step1中keystore密码
 step4:
  访问https://localhost:8443进行测试
 2、修改spring配置文件: 
 step1:添加channelProcessingFilter,注意,其位置应是过滤器链中的第一个。
 step2:
 <!-- HTTPS安全通道 -->
 <bean id="channelProcessingFilter"
  class="org.acegisecurity.securechannel.ChannelProcessingFilter">
  <property name="channelDecisionManager" ref="channelDecisionManager"/>
  <property name="filterInvocationDefinitionSource">
   <value>
    CONVERT_URL_TO_UPPERCASE_BEFORE_COMPARISON
    /A/index.jsp.*/Z=REQUIRES_SECURE_CHANNEL
    /A/j_acegi_security_check.*/Z=REQUIRES_SECURE_CHANNEL
    /A.*/Z=REQUIRES_INSECURE_CHANNEL
   </value>
  </property>
 </bean>
 <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>
 注意:channelProcessingFilter配置时,其filterInvocationDefinitionSource属性,要使用
 正则表达式风格的URL路径匹配,此时,需要添加一个库,则ORO库。
  

 

 

 

 

原创粉丝点击