首先说明,我用的是0.8.3版本。因为已经弄得差不多了,另外,看的一些材料都是针对0.8.3版本的,好像后面的版本跟0.8.3还是有不少的不同,所以也就不想换成新版本了。
因为系统中可能存在两种类型的账号,一种是常见的用户名+密码,另一种是用认证锁(像IKey之类的),所以配了两个provider:
<bean id="authenticationManager"
class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="authenticationProvider" /><!--对于第一种账号-->
<ref bean="authenticationProvider4Ikey" /><!--对于第二种账号-->
</list>
</property>
</bean>
按书上说的,Acegi会遍历这些provider来进行验证。结果发现当我用第一种账号时,可以正常进行验证,可是用第二种时就无法通过验证(当然了,前提是这个账号是存在的)。检查配置,没发现什么错,很奇怪。把两个provider的顺序换了一下,现在第二种账号可以正常进行验证,可是第一种类型的却不行了。看来问题是出现在遍历这些provider上了。
找了Acegi的原码来看,发现当使用provider进行验证时,如果第一个验证失败,则会用下一个provider进行验证,直至验证通过或是遍历完所有的provider。的确跟书上说的一样,可是怎么实际用起来就出错呢?实在看不出头绪,只好Debug,一步一步跟踪。终于发现问题所在。原来在provider验证失败后抛出异常,而在ProviderManager#doAuthentication()并没有对这个异常进行捕获,于是这个异常就接着很上抛了,结果是当第一个provider验证失败后,就会因为异常的出现而终止了doAuthentication()方法,所以后面的provider根本就没有机会发挥作用。
找到问题所在了,接下来就是改了,最简单的作法当然就是在ProviderManager#doAuthentication()中加上对这个异常的捕获:
try{
Authentication result = provider.authenticate(authentication);
if (result != null) {
sessionController.afterAuthentication(authentication, result);
return result;
}
}catch(Exception e){
//TODO
}
估计这个问题在后面的版本中应该是有改正了吧,找来1.0.1版本的原码,果然:
try {
result = provider.authenticate(authentication);
sessionController.checkAuthenticationAllowed(result);
} catch (AuthenticationException ae) {
lastException = ae;
result = null;
}
也不知道0.8.3版本会不会还存在其他一些问题,看来还是得找个时间把Acegi换成最新的版本,本还想偷懒一下的。