zoukankan      html  css  js  c++  java
  • 菜鸟-手把手教你把Acegi应用到实际项目中(5)

    在实际企业应用中,用户密码一般都会进行加密处理,这样才能使企业应用更加安全。既然密码的加密如此之重要,那么Acegi(Spring Security)作为成熟的安全框架,当然也我们提供了相应的处理方式。

        针对用户密码的加密工作,DaoAuthenticationProvider同时暴露了passwordEncoder和saltSource属性。PasswordEncoder和SaltSource是可选的属性,PasswordEncoder负责对认证库中的密码进行加解密。而SaltSource则是在产生密码时给它加点“盐”,以增强密码在认证库中的安全性。Acegi安全系统提供的PasswordEncoder实现中包括MD5、SHA和明文编码。
    Acegi提供了三种加密器:
     PlaintextPasswordEncoder---默认,不加密,返回明文.
     ShaPasswordEncoder---哈希算法(SHA)加密
     Md5PasswordEncoder---消息摘要(MD5)加密

    Acegi安全系统提供了两个SaltSource的实现:
     SystemWideSaltSource,它用同样的"盐"对系统中所有的密码进行编码
     ReflectionSaltSource只对从UserDetails对象返回的获得这种"盐"的指定属性进行检查。请参考JavaDoc以获取对这些可选特性的更详细信息。

          图1为Acegi内置的PasswordEncoder继承链。默认时,DaoAuthenticationProvider会实例化PlaintextPasswordEncoder对象,即应对用户密码未进行加密处理的情况。

     PasswordEncoder继承链

          图2为Acegi内置的SaltSource继承链。默认时,SaltSource的取值为null,即未启用密码私钥。

    SaltSource继承链

    1、 PlaintextPasswordEncoder明文密码
          在使用明文密码期间,如果系统允许登录用户不区分密码大小写,则应设置ignorePasswordCase属性值为true。
     在Acegi安全配置文件中添加:

    Xml代码 复制代码 收藏代码
    1. <bean id="daoAuthenticationProvider"  
    2.     class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
    3.     <property name="userDetailsService" ref="inMemDaoImpl" />  
    4.     <!-- 增加 -->  
    5.     <property name="passwordEncoder" ref="plaintextPasswordEncoder" />  
    6. </bean>  
    7.   
    8. <!-- 增加 -->  
    9. <bean id="plaintextPasswordEncoder"  
    10.     class="org.acegisecurity.providers.encoding.PlaintextPasswordEncoder">  
    11.     <property name="ignorePasswordCase" value="true"></property>  
    12. </bean>  
    <bean id="daoAuthenticationProvider"
    	class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    	<property name="userDetailsService" ref="inMemDaoImpl" />
    	<!-- 增加 -->
    	<property name="passwordEncoder" ref="plaintextPasswordEncoder" />
    </bean>
    
    <!-- 增加 -->
    <bean id="plaintextPasswordEncoder"
    	class="org.acegisecurity.providers.encoding.PlaintextPasswordEncoder">
    	<property name="ignorePasswordCase" value="true"></property>
    </bean>
    

    2、 ShaPasswordEncoder哈希算法(SHA)加密
          在Acegi安全配置文件中添加:

    Xml代码 复制代码 收藏代码
    1. <bean id="daoAuthenticationProvider"  
    2.     class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
    3.     <property name="userDetailsService" ref="inMemDaoImpl" />  
    4.     <!-- 增加 -->  
    5.     <property name="passwordEncoder" ref="shaPasswordEncoder" />  
    6.     <!-- <property name="passwordEncoder" ref="shaMessageDigestPasswordEncoder" /> -->  
    7. </bean>  
    8.   
    9. <!-- 增加, 以下两种配置方式等效 -->  
    10. <bean id="shaPasswordEncoder"  
    11.     class="org.acegisecurity.providers.encoding.ShaPasswordEncoder">  
    12.     <constructor-arg>  
    13.         <value>256</value>  
    14.     </constructor-arg>  
    15.     <property name="encodeHashAsBase64" value="false"></property>  
    16. </bean>  
    17. <!--    
    18. <bean id="shaMessageDigestPasswordEncoder"  
    19.     class="org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder">  
    20.     <constructor-arg>  
    21.         <value>SHA-256</value>  
    22.     </constructor-arg>  
    23.     <property name="encodeHashAsBase64" value="false"></property>  
    24. </bean>  
    25.  -->  
    <bean id="daoAuthenticationProvider"
    	class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    	<property name="userDetailsService" ref="inMemDaoImpl" />
    	<!-- 增加 -->
    	<property name="passwordEncoder" ref="shaPasswordEncoder" />
    	<!-- <property name="passwordEncoder" ref="shaMessageDigestPasswordEncoder" /> -->
    </bean>
    
    <!-- 增加, 以下两种配置方式等效 -->
    <bean id="shaPasswordEncoder"
    	class="org.acegisecurity.providers.encoding.ShaPasswordEncoder">
    	<constructor-arg>
    		<value>256</value>
    	</constructor-arg>
    	<property name="encodeHashAsBase64" value="false"></property>
    </bean>
    <!-- 
    <bean id="shaMessageDigestPasswordEncoder"
    	class="org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder">
    	<constructor-arg>
    		<value>SHA-256</value>
    	</constructor-arg>
    	<property name="encodeHashAsBase64" value="false"></property>
    </bean>
     -->
    

    3、 Md5PasswordEncoder消息摘要(MD5)加密
          在Acegi安全配置文件中添加:

    Xml代码 复制代码 收藏代码
    1. <bean id="daoAuthenticationProvider"  
    2.     class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
    3.     <property name="userDetailsService" ref="inMemDaoImpl" />  
    4.     <!-- 增加 -->  
    5.     <property name="passwordEncoder" ref="md5PasswordEncoder" />  
    6.     <!-- <property name="passwordEncoder" ref="md5MessageDigestPasswordEncoder" /> -->  
    7. </bean>  
    8.   
    9. <!-- 增加. 以下两种配法等效 -->  
    10. <bean id="md5PasswordEncoder"  
    11.     class="org.acegisecurity.providers.encoding.Md5PasswordEncoder">  
    12.     <property name="encodeHashAsBase64" value="false"></property>  
    13. </bean>  
    14. <!--    
    15. <bean id="md5MessageDigestPasswordEncoder"  
    16.     class="org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder">  
    17.     <constructor-arg>  
    18.         <value>MD5</value>  
    19.     </constructor-arg>  
    20.     <property name="encodeHashAsBase64" value="false"></property>  
    21. </bean>  
    22.  -->  
    <bean id="daoAuthenticationProvider"
    	class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    	<property name="userDetailsService" ref="inMemDaoImpl" />
    	<!-- 增加 -->
    	<property name="passwordEncoder" ref="md5PasswordEncoder" />
    	<!-- <property name="passwordEncoder" ref="md5MessageDigestPasswordEncoder" /> -->
    </bean>
    
    <!-- 增加. 以下两种配法等效 -->
    <bean id="md5PasswordEncoder"
    	class="org.acegisecurity.providers.encoding.Md5PasswordEncoder">
    	<property name="encodeHashAsBase64" value="false"></property>
    </bean>
    <!-- 
    <bean id="md5MessageDigestPasswordEncoder"
    	class="org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder">
    	<constructor-arg>
    		<value>MD5</value>
    	</constructor-arg>
    	<property name="encodeHashAsBase64" value="false"></property>
    </bean>
     -->
    

    4、 SystemWideSaltSource
          SystemWideSaltSource会采用一个静态字符串表示密码私钥(salt),所有用户的密码处理都会采用这一私钥。同未启用密码私钥相比,SystemWideSaltSource更为安全,因为它使得密码的破解变得更困难。默认时,它会采用“密码{密码私钥}”形式加密密码。
          配置如下:

    Xml代码 复制代码 收藏代码
    1. <bean id="daoAuthenticationProvider"  
    2.     class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
    3.     <property name="userDetailsService" ref="userDetailsService" />  
    4.     <property name="passwordEncoder" ref="md5PasswordEncoder" /><!-- 增加 -->  
    5.        
    6.     <!-- 增加 -->  
    7.     <property name="saltSource">  
    8.         <bean  
    9.             class="org.acegisecurity.providers.dao.salt.SystemWideSaltSource">  
    10.             <property name="systemWideSalt" value="javaee"></property>  
    11.         </bean>  
    12.     </property>  
    13. </bean>  
    <bean id="daoAuthenticationProvider"
    	class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    	<property name="userDetailsService" ref="userDetailsService" />
    	<property name="passwordEncoder" ref="md5PasswordEncoder" /><!-- 增加 -->
    	
    	<!-- 增加 -->
    	<property name="saltSource">
    		<bean
    			class="org.acegisecurity.providers.dao.salt.SystemWideSaltSource">
    			<property name="systemWideSalt" value="javaee"></property>
    		</bean>
    	</property>
    </bean>
    

    5、 ReflectionSaltSource
          尽管采用SystemWideSaltSource能够加强密码的保护,但由于SystemWideSaltSource采用了全局性质的密码私钥,因此仍存在一定的缺陷。
          而ReflectionSaltSource采用了个案性质的密码私钥,即其密码加密所采用的私钥是动态变化的,因此它更为安全。ReflectionSaltSource仍采用“密码{密码私钥}”的形式加密密码。
          配置如下:

    Xml代码 复制代码 收藏代码
    1. <bean id="daoAuthenticationProvider"  
    2.     class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
    3.     <property name="userDetailsService" ref="userDetailsService" />  
    4.     <property name="passwordEncoder" ref="md5PasswordEncoder" />  
    5.        
    6.     <!-- 增加 -->  
    7.     <property name="saltSource">  
    8.         <bean  
    9.             class="org.acegisecurity.providers.dao.salt.ReflectionSaltSource">  
    10.             <property name="userPropertyToUse" value="getUsername"></property>  
    11.         </bean>  
    12.     </property>  
    13. </bean>  
    <bean id="daoAuthenticationProvider"
    	class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    	<property name="userDetailsService" ref="userDetailsService" />
    	<property name="passwordEncoder" ref="md5PasswordEncoder" />
    	
    	<!-- 增加 -->
    	<property name="saltSource">
    		<bean
    			class="org.acegisecurity.providers.dao.salt.ReflectionSaltSource">
    			<property name="userPropertyToUse" value="getUsername"></property>
    		</bean>
    	</property>
    </bean>
    

          此时,ReflectionSaltSource将调用UserDetails对象的getUsername()方法获得各用户的密码私钥。比如:javaee(用户名)/password(密码) 用户的密码将被以“password{javaee}”的形式进行加密处理。
           通过指定userPropertyToUse属性的值,开发者能够控制密码私钥的来源。比如上述的getUsername的含义就是动态调用相应的getUsername()方法,并将返回结果直接作为密码的私钥。在实际企业应用中,Acegi应用开发者可能会提供自身的UserDetails实现类,这时userPropertyToUse属性的取值范围更加广泛。

     6、 在web.xml中,我提供了三种方式方便大家调试

    Xml代码 复制代码 收藏代码
    1. <!--    
    2.     <context-param>  
    3.     <param-name>contextConfigLocation</param-name>  
    4.     <param-value>  
    5.     /WEB-INF/applicationContext-acegi-security-plaintext.xml   
    6.     </param-value>  
    7.     </context-param>  
    8. -->  
    9.   
    10. <!--    
    11.     <context-param>  
    12.     <param-name>contextConfigLocation</param-name>  
    13.     <param-value>  
    14.     /WEB-INF/applicationContext-acegi-security-sha.xml   
    15.     </param-value>  
    16.     </context-param>  
    17. -->  
    18.   
    19. <context-param>  
    20.     <param-name>contextConfigLocation</param-name>  
    21.     <param-value>  
    22.         /WEB-INF/applicationContext-acegi-security-md5.xml   
    23.     </param-value>  
    24. </context-param>  
    25.   
    26. <!--    
    27. <context-param>  
    28.     <param-name>contextConfigLocation</param-name>  
    29.     <param-value>  
    30.         /WEB-INF/applicationContext-acegi-security-md5-salt.xml   
    31.     </param-value>  
    32. </context-param>-->  
    <!-- 
    	<context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>
    	/WEB-INF/applicationContext-acegi-security-plaintext.xml
    	</param-value>
    	</context-param>
    -->
    
    <!-- 
    	<context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>
    	/WEB-INF/applicationContext-acegi-security-sha.xml
    	</param-value>
    	</context-param>
    -->
    
    <context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>
    		/WEB-INF/applicationContext-acegi-security-md5.xml
    	</param-value>
    </context-param>
    
    <!-- 
    <context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>
    		/WEB-INF/applicationContext-acegi-security-md5-salt.xml
    	</param-value>
    </context-param>-->
    

     7、 这里我提供了一个用于生成加密密码的类

    Java代码 复制代码 收藏代码
    1. package org.acegi.sample;   
    2.   
    3.   
    4. import org.acegisecurity.providers.encoding.Md5PasswordEncoder;   
    5. import org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder;   
    6. import org.acegisecurity.providers.encoding.ShaPasswordEncoder;   
    7. import org.apache.commons.logging.Log;   
    8. import org.apache.commons.logging.LogFactory;   
    9.   
    10. /**  
    11.  * 加密管理类  
    12.  *   
    13.  * @author zhanjia  
    14.  *  
    15.  */  
    16. public class PasswordProcessing {   
    17.   
    18.     private static final Log log = LogFactory.getLog(PasswordProcessing.class);   
    19.        
    20.     public static void processMd5() {   
    21.         log.info("以MD5方式加密......................");   
    22.            
    23.         // 直接指定待采用的加密算法(MD5)   
    24.         MessageDigestPasswordEncoder mdpeMd5 = new MessageDigestPasswordEncoder("MD5");   
    25.         // 生成32位的Hex版, 这也是encodeHashAsBase64的默认值   
    26.         mdpeMd5.setEncodeHashAsBase64(false);   
    27.         log.info(mdpeMd5.encodePassword("password"null));   
    28.         // 生成24位的Base64版   
    29.         mdpeMd5.setEncodeHashAsBase64(true);   
    30.         log.info(mdpeMd5.encodePassword("password"null));   
    31.            
    32.         // 等效于上述代码   
    33.         Md5PasswordEncoder mpe = new Md5PasswordEncoder();   
    34.         mpe.setEncodeHashAsBase64(false);   
    35.         log.info(mpe.encodePassword("password"null));   
    36.         mpe.setEncodeHashAsBase64(true);   
    37.         log.info(mpe.encodePassword("password"null));   
    38.     }   
    39.        
    40.     public static void processSha() {   
    41.         log.info("以SHA方式加密......................");   
    42.            
    43.         // 直接指定待采用的加密算法(SHA)及加密强度(256)   
    44.         MessageDigestPasswordEncoder mdpeSha = new MessageDigestPasswordEncoder("SHA-256");   
    45.         mdpeSha.setEncodeHashAsBase64(false);   
    46.         log.info(mdpeSha.encodePassword("password"null));   
    47.         mdpeSha.setEncodeHashAsBase64(true);   
    48.         log.info(mdpeSha.encodePassword("password"null));   
    49.            
    50.         // 等效于上述代码   
    51.         ShaPasswordEncoder spe = new ShaPasswordEncoder(256);          
    52.         spe.setEncodeHashAsBase64(false);   
    53.         log.info(spe.encodePassword("password"null));   
    54.         spe.setEncodeHashAsBase64(true);   
    55.         log.info(spe.encodePassword("password"null));   
    56.     }   
    57.        
    58.     public static void processSalt() {   
    59.         log.info("以MD5方式加密、加私钥(盐)......................");   
    60.            
    61.         Md5PasswordEncoder mpe = new Md5PasswordEncoder();   
    62.         mpe.setEncodeHashAsBase64(false);   
    63.            
    64.         // 等效的两行地代码   
    65.         log.info(mpe.encodePassword("password{javaee}"null)); // javaee为密码私钥   
    66.         log.info(mpe.encodePassword("password""javaee")); // javaee为密码私钥   
    67.         // 结果:87ce7b25b469025af0d5c6752038fb56   
    68.     }   
    69.        
    70.     /**  
    71.      * @param args  
    72.      */  
    73.     public static void main(String[] args) {   
    74.         processMd5();   
    75.         processSha();   
    76.         processSalt();   
    77.     }   
    78.   
    79. }  
    package org.acegi.sample;
    
    
    import org.acegisecurity.providers.encoding.Md5PasswordEncoder;
    import org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder;
    import org.acegisecurity.providers.encoding.ShaPasswordEncoder;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * 加密管理类
     * 
     * @author zhanjia
     *
     */
    public class PasswordProcessing {
    
    	private static final Log log = LogFactory.getLog(PasswordProcessing.class);
    	
    	public static void processMd5() {
    		log.info("以MD5方式加密......................");
    		
    		// 直接指定待采用的加密算法(MD5)
    		MessageDigestPasswordEncoder mdpeMd5 = new MessageDigestPasswordEncoder("MD5");
    		// 生成32位的Hex版, 这也是encodeHashAsBase64的默认值
    		mdpeMd5.setEncodeHashAsBase64(false);
    		log.info(mdpeMd5.encodePassword("password", null));
    		// 生成24位的Base64版
    		mdpeMd5.setEncodeHashAsBase64(true);
    		log.info(mdpeMd5.encodePassword("password", null));
    		
    		// 等效于上述代码
    		Md5PasswordEncoder mpe = new Md5PasswordEncoder();
    		mpe.setEncodeHashAsBase64(false);
    		log.info(mpe.encodePassword("password", null));
    		mpe.setEncodeHashAsBase64(true);
    		log.info(mpe.encodePassword("password", null));
    	}
    	
    	public static void processSha() {
    		log.info("以SHA方式加密......................");
    		
    		// 直接指定待采用的加密算法(SHA)及加密强度(256)
    		MessageDigestPasswordEncoder mdpeSha = new MessageDigestPasswordEncoder("SHA-256");
    		mdpeSha.setEncodeHashAsBase64(false);
    		log.info(mdpeSha.encodePassword("password", null));
    		mdpeSha.setEncodeHashAsBase64(true);
    		log.info(mdpeSha.encodePassword("password", null));
    		
    		// 等效于上述代码
    		ShaPasswordEncoder spe = new ShaPasswordEncoder(256);		
    		spe.setEncodeHashAsBase64(false);
    		log.info(spe.encodePassword("password", null));
    		spe.setEncodeHashAsBase64(true);
    		log.info(spe.encodePassword("password", null));
    	}
    	
    	public static void processSalt() {
    		log.info("以MD5方式加密、加私钥(盐)......................");
    		
    		Md5PasswordEncoder mpe = new Md5PasswordEncoder();
    		mpe.setEncodeHashAsBase64(false);
    		
    		// 等效的两行地代码
    		log.info(mpe.encodePassword("password{javaee}", null)); // javaee为密码私钥
    		log.info(mpe.encodePassword("password", "javaee")); // javaee为密码私钥
    		// 结果:87ce7b25b469025af0d5c6752038fb56
    	}
    	
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		processMd5();
    		processSha();
    		processSalt();
    	}
    
    }
    

    开发环境:
    MyEclipse 5.0GA
    Eclipse3.2.1
    JDK1.5.0_10
    tomcat5.5.23
    acegi-security-1.0.7
    Spring2.0

    Jar包:
    acegi-security-1.0.7.jar
    Spring.jar(2.0.8)
    commons-codec.jar
    jstl.jar (1.1)
    standard.jar
    commons-logging.jar(1.0)



     

  • 相关阅读:
    javascript 调试代码
    简洁的js拖拽代码
    搭个小窝
    FastDFS随笔
    JDK6和JDK7中String的substring()方法及其差异
    杂笔
    JVM内存随笔
    java中的final和volatile详解
    关于java的Synchronized,你可能需要知道这些(下)
    关于java的Synchronized,你可能需要知道这些(上)
  • 原文地址:https://www.cnblogs.com/wzh123/p/3392999.html
Copyright © 2011-2022 走看看