众所周知,在多个realm环境下:
shiro的默认认证策略是AtLeastOneSuccessfulStrategy它不需要配置。
但是在认证策略体系中还有其它两个认证策略,它们分别是:
看一下各自得定义吧:
FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;(注:这里"第一个"指的是认证成功得那一个realm)
AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulSTRATEGY不同,将返回所有Realm身份验证成功的认证信息;
AllSuccessfulStrategy:所有Realm验证成功过才算成功,且返回所有Realm身份验证的认证信息,如果有一个失败就失败。
AtLeastOneSuccessfulStrategy为默认配置,AllSuccessfulStrategy配置也比较简单.。
但是FirstSuccessfulStrategy,它会有个隐藏的属性,这个属性不是很好找,到现在我都没找到它,为了节约时间我就不去找了。
这个属性是——stopAfterFirstSuccess,(如果不是通过debug发现了这个属性,我到现在也不会得到正确的实验结果)。
因为在FirstSuccessfulStrategy里根本发现不了这个属性,不信请看shiro1.5.3源码:
FirstSuccessfulStrategy.java
package org.apache.shiro.authc.pam; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.realm.Realm; import org.apache.shiro.util.CollectionUtils; import java.util.Collection; /** * {@link AuthenticationStrategy} implementation that only accepts the account data from * the first successfully consulted Realm and ignores all subsequent realms. This is slightly * different behavior than {@link AtLeastOneSuccessfulStrategy}, so please review both to see * which one meets your needs better. * * @see AtLeastOneSuccessfulStrategy AtLeastOneSuccessfulAuthenticationStrategy * @since 0.9 */ public class FirstSuccessfulStrategy extends AbstractAuthenticationStrategy { /** * Returns {@code null} immediately, relying on this class's {@link #merge merge} implementation to return * only the first {@code info} object it encounters, ignoring all subsequent ones. */ public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException { return null; } /** * Returns the specified {@code aggregate} instance if is non null and valid (that is, has principals and they are * not empty) immediately, or, if it is null or not valid, the {@code info} argument is returned instead. * <p/> * This logic ensures that the first valid info encountered is the one retained and all subsequent ones are ignored, * since this strategy mandates that only the info from the first successfully authenticated realm be used. */ protected AuthenticationInfo merge(AuthenticationInfo info, AuthenticationInfo aggregate) { if (aggregate != null && !CollectionUtils.isEmpty(aggregate.getPrincipals())) { return aggregate; } return info != null ? info : aggregate; } }
通过debug获得得真相
虽然看不到这个属性,但它的确存在,那么我是怎么知道它存在呢?
在applicationContext.xml里配置多realm认证环境:(注:这样配置的话,就永远不会看清FirstSuccessfulStrategy)
<!-- 多个realm时需要配置——ModularRealmAuthenticator--> <bean id ="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator"> <property name="realms"> <list> <ref bean="jdbcRealm"/> <ref bean="jdbcRealm2"/> </list> </property> <property name="authenticationStrategy"> <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"></bean> </property> </bean>
debug看一下,(前提配置了多个realm环境,并且可以debug到这一步):
可以看到该策略下(FirstSuccessfulStrategy),有一个stopAfterFirstSuccess属性,默认是false。
默认false会是什么结果?
结果就是:
当前的配置和AtLeastOneSuccessfulStrategy配置效果一样,基本没有变化。
也就是说,第一个realm即便是验证通过,那它还是会去验证第二个realm。
可以看一下后台打印:
代码已经来到了:MyShiroRealm授权区域1-----> 通过realm-----没有异常! 代码已经来到了:MyShiroRealm授权区域2-----> 通过realm-----没有异常!
那么如果把stopAfterFirstSuccess属性改成true呢?
<!-- 多个realm时需要配置——ModularRealmAuthenticator--> <bean id ="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator"> <property name="realms"> <list> <ref bean="jdbcRealm"/> <ref bean="jdbcRealm2"/> </list> </property> <property name="authenticationStrategy"> <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"> <property name="stopAfterFirstSuccess" value="true"></property> </bean> </property> </bean>
再次debug:(观察变化)
这次stopAfterFirstSuccess属性的值为true,也就是说只要第一个realm通过认证,那么就不会匹配第二个realm了。
再看一下控制台打印,确实出现第一个通过认证的realm就不会接着认证了(注:如果第一个realm没有被认证就会接着认证其它realm,直到出现第一个通过认证的realm):
代码已经来到了:MyShiroRealm授权区域1-----> 通过realm-----没有异常!
总结:想要看到FirstSuccessfulStrategy真正的效果,需要在spring的bean里配置stopAfterFirstSuccess属性为true,否则认证效果将等同于AtLeastOneSuccessfulStrategy。
好啦,如果你读懂了我的结论,那么将会解决你的一部分困惑。