年刚过,还很懒,这个东东年前都开始关注了,今天把学习成果总结一下。
Acegi,一个安全系统,拦截器和面向接口的编程方式,支持ACL、JAAS基于Spring.我的理解其价值在于:replace Container-Managed Authentication,将安全这一块脱离具体j2ee容器,将来需要迁移时少一些麻烦,它足够强大,可以给web系统甚至cs应用提供足够的安全保护机制。这是一个常用的轮子,造得不错哟。
不过,acegi的学习曲线很陡峭,在web.xml配置了一堆的Filter之后,还需要配置spring的bean,仍然是一堆,好在先跑起了demo(0.6.1 quick-start)增加了一点信心。
先记下一个概念:
Authentication 认证:验证一个用户的身份,你说你是大人物某某,你说是就是呀,请看证件,或介绍信等。最常用的是用户名+口令,还有电子证书等.
在 bean 配置中,需要关注的几个关键bean,在后面的扩展中需要用到:
1 AuthenticationManager 用于认证ContextHolder中的Authentication对象。给多种的认证方式留下了接口。
2 AccessDecissionManager 用于授权一个特定的操作,这里有一个授权策略问题,三个实现类分别为:
AffirmativeBased 只需有一个投票赞成即可通过(最常用);allowIfAllAbstainDecisions属性值默认为false,意思是如果所有的授权投票是都是弃权,则通不过授权检查。
ConsensusBased 需要大多数投票赞成即可通过;
UnanimousBased 需要所有的投票赞成才能通过(悲观吧)。
3 ObjectDefinitionSource 描述角色与资源的匹配方式。
以上三个bean装配成为一个filterInvocationInterceptor,它将用来组装securityEnforcementFilter,之后的bean先不考虑了,因为扩展时用不到,照抄即可。
例子是比较简易的,要想让应用在实际项目中,首先需要解决以下两个问题:
1 基于数据库的用户认证,一般是用户名+密码,我的作法是:
1.1 使你的User(Pojo或domain object)实现acegi中的这个接口:UserDetails,当然,如果你不想这么作,也可以加一个中间层,包装一下啦。
这个接口只有一个方法 public GrantedAuthority[] getAuthorities();即返回该用户的角色列表.
1.2 自己实现这个接口PasswordAuthenticationDao,不管你用hibernate还是ibatis.
public UserDetails loadUserByUsernameAndPassword(String username, String password);
很明显,需要从数据库中验证用户名和口令。
1.3 开始装配:
<bean id="myPwdAuthenticationDAO" class="net.chage.sm.dao.ibatis.AuthenticationDAOiBatis">
<property name="dataSource"> <ref bean="dataSource" /> </property>
<property name="sqlMapClient"><ref bean="sqlMap"/></property>
</bean>
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.PasswordDaoAuthenticationProvider">
<property name="passwordAuthenticationDao"><ref bean="myPwdAuthenticationDAO"/></property>
<property name="userCache"><ref local="userCache"/></property>
</bean>
2 例子中url和角色的匹配关系也是固定的,如下:
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=ROLE_ADMIN
/contract.do*=ROLE_XXX
</value>
</property>
如果这一块也需要从database中取,可以这么来实现:新建一个类extending PathBasedFilterInvocationDefinitionMap,
使用其addSecureUrl来增加匹配信息。我写的是一个超简单的类,只为说明问题:
package com.head.acegisecurity;
import net.sf.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import net.sf.acegisecurity.ConfigAttribute;
public class CjObjectDefinitionSource extends
PathBasedFilterInvocationDefinitionMap {
public CjObjectDefinitionSource(){
super();
ConfigAttributeDefinition definition = new ConfigAttributeDefinition();
ConfigAttribute att = new MyConfigAttribute();
definition.addConfigAttribute(att);
this.addSecureUrl("/admin/**",definition);
}
class MyConfigAttribute implements ConfigAttribute{
public String getAttribute(){
return "ROLE_ADMIN";
}
}
}
然后配置:
<bean id="myObjectDefinitionSource" class="com.head.acegisecurity.CjObjectDefinitionSource"/>
<bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="accessDecisionManager"/></property>
<property name="objectDefinitionSource"><ref local="myObjectDefinitionSource"/></property>
</bean>
最后,再说一下,acegi确实是一个优秀的安全框架,灵活强大,即使你用不上它,也可以从它的设计中汲取灵感。