shiro的FirstSuccessfulStrategy正确配置方式

众所周知,在多个realm环境下:

shiro的默认认证策略是AtLeastOneSuccessfulStrategy它不需要配置。

但是在认证策略体系中还有其它两个认证策略,它们分别是:

shiro的FirstSuccessfulStrategy正确配置方式

看一下各自得定义吧:

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到这一步):

shiro的FirstSuccessfulStrategy正确配置方式

可以看到该策略下(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:(观察变化)

shiro的FirstSuccessfulStrategy正确配置方式

这次stopAfterFirstSuccess属性的值为true,也就是说只要第一个realm通过认证,那么就不会匹配第二个realm了。

再看一下控制台打印,确实出现第一个通过认证的realm就不会接着认证了(注:如果第一个realm没有被认证就会接着认证其它realm,直到出现第一个通过认证的realm):

代码已经来到了:MyShiroRealm授权区域1----->
通过realm-----没有异常!

总结:想要看到FirstSuccessfulStrategy真正的效果,需要在spring的bean里配置stopAfterFirstSuccess属性为true,否则认证效果将等同于AtLeastOneSuccessfulStrategy。

好啦,如果你读懂了我的结论,那么将会解决你的一部分困惑。

 

上一篇:GAT1400的注册流程RFC2617认证


下一篇:android-Realm Java-如何在查询多个ID时保持项目顺序?