菜鸟-手把手教你把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对象,即应对用户密码未进行加密处理的情况。
图2为Acegi内置的SaltSource继承链。默认时,SaltSource的取值为null,即未启用密码私钥。
1、 PlaintextPasswordEncoder明文密码
在使用明文密码期间,如果系统允许登录用户不区分密码大小写,则应设置ignorePasswordCase属性值为true。
在Acegi安全配置文件中添加:
- <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>
<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安全配置文件中添加:
- <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>
- -->
<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安全配置文件中添加:
- <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>
- -->
<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更为安全,因为它使得密码的破解变得更困难。默认时,它会采用“密码{密码私钥}”形式加密密码。
配置如下:
- <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>
<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仍采用“密码{密码私钥}”的形式加密密码。
配置如下:
- <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>
<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中,我提供了三种方式方便大家调试
- <!--
- <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>-->
<!--
<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、 这里我提供了一个用于生成加密密码的类
- 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();
- }
- }
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)
- 例子源码_5_Acegi4.rar (17 KB)
- 下载次数: 599
菜鸟-手把手教你把Acegi应用到实际项目中(5)的更多相关文章
- 菜鸟-手把手教你把Acegi应用到实际项目中(8)-扩展UserDetailsService接口
一个能为DaoAuthenticationProvider提供存取认证库的的类,它必须要实现UserDetailsService接口: public UserDetails loadUserByUse ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(10)-保护业务方法
前面已经讲过关于保护Web资源的方式,其中包括直接在XML文件中配置和自定义实现FilterInvocationDefinitionSource接口两种方式.在实际企业应用中,保护Web资源显得非常重 ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(1.1)
相信不少朋友们对于学习Acegi的过程是比较痛苦的,而且可能最初一个例子都没能真正运行起来.即使能运行起来,对于里面那么多的配置,更搞不清楚为什么要那么配,多配一个和少配一个究竟有什么区别? 最终头都 ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(11)-切换用户
在某些应用场合中,我们可能需要用到切换用户的功能,从而以另一用户的身份进行相关操作.这一点类似于在Linux系统中,用su命令切换到另一用户进行相关操作. 既然实际应用中有这种场合,那么我们 ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(12)-Run-As认证服务
有这样一些场合,系统用户必须以其他角色身份去操作某些资源.例如,用户A要访问资源B,而用户A拥有的角色为AUTH_USER,资源B访问的角色必须为AUTH_RUN_AS_DATE,那么此时就必须使用户 ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(7)-缓存用户信息
首先讲讲EhCache.在默认情况下,即在用户未提供自身配置文件ehcache.xml或ehcache-failsafe.xml时,EhCache会依据其自身Jar存档包含的ehcache-fails ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(4)
今天就讲个ConcurrentSessionFilter. 在Acegi 1.x版本中,控制并发HttpSession和Remember-Me认证服务不能够同时启用,它们之间存在冲突问题,这是该版本的 ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(6)
在企业应用中,用户的用户名.密码和角色等信息一般存放在RDBMS(关系数据库)中.前面几节我们采用的是InMemoryDaoImpl,即基于内存的存放方式.这节我们将采用RDBMS存储用户信息. Us ...
- 菜鸟-手把手教你把Acegi应用到实际项目中(1.2)
7) daoAuthenticationProvider 进行简单的基于数据库的身份验证.DaoAuthenticationProvider获取数据库中的账号密码并进行匹配,若成功则在通过用户身份的同 ...
随机推荐
- 通用的业务编码规则设计实现[转:http://www.cnblogs.com/xqin/p/3708367.html]
一.背景 每一个企业应用中不可避免的都会涉及到业务编码规则的问题,比如订单管理系统中的订单编号,比如商品管理系统中的商品编码,比如项目管理系统中的项目编码等等,这一系列的编码都需要管理起来,那么它们的 ...
- nova分析(9)—— nova-novncproxy
nova提供了novncproxy代理支持用户通过vnc来访问虚拟机,用户可以通过websocket.java客户端或者spicehtml5来访问.通过websket访问虚拟机的功能已经集成到hori ...
- jQuery实现表单验证
表单是网页的一个重要组成部分.本节做一个简单的表单提交网页然后利用jQuery实现表单的验证.后续的表单完善以及功能的完善会在以后的博客中给出. 效果图: 代码: <!DOCTYPE html ...
- json换行符的处理
JS端的: var s = JSON.stringify(str); var ss = s.replace(/\\n/g, "\\n") .replace(/\\'/g, &quo ...
- Oracle与MySQL的几点区别
Oracle数据库与MySQL数据库的区别是本文我们主要介绍的内容,希望能够对您有所帮助. 1.组函数用法规则 mysql中组函数在select语句中可以随意使用,但在oracle中如果查询语句中有组 ...
- Hadoop:实战Web日志分析
示例场景 日志说明 有两台Web服务器,日志文件存放在/usr/local/nginx/logs/目录,日志默认为nginx定义格式.如: 123.13.17.13 - - [25/Aug/2016: ...
- SVN学习之svn命令行下的基本操作
http://huihai.iteye.com/blog/1985751 上一节已经把svn安装完成,下来就用命令行做一些简单的操作. 1.当svn安装完成后,svn管理人员会在svn的root根目录 ...
- C# new 和 override.
http://www.dotblogs.com.tw/skychang/archive/2012/05/10/72114.aspx?fid=60865
- CF 518 D. Ilya and Escalator
Ilya got tired of sports programming, left university and got a job in the subway. He was given the ...
- POJ 3187 杨辉三角+枚举排列 好题
如果给出一个由1~n组成的序列,我们可以每相邻2个数求和,得到一个新的序列,不断重复,最后得到一个数sum, 现在输入n,sum,要求输出一个这样的排列,如果有多种情况,输出字典序最小的那一个. 刚开 ...