wzh123

博客园 首页 新随笔 联系 订阅 管理

在实际企业应用中,用户密码一般都会进行加密处理,这样才能使企业应用更加安全。既然密码的加密如此之重要,那么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)



 

posted on 2013-10-28 19:58  wzh123  阅读(341)  评论(0编辑  收藏  举报