• shiro1.5.2中FirstSuccessfulStrategy正确配置方式


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

    AuthenticationStrategy是一个接口,同时它的实现类对象,对应ModularRealmAuthenticator里的属性。

    AuthenticationStrategy接口有三个实现类:

    看一下各自得定义吧:

    FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;(注:这里"第一个"指的是认证成功得那一个realm)

    AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulSTRATEGY不同,将返回所有Realm身份验证成功的认证信息;
    AllSuccessfulStrategy:所有Realm验证成功过才算成功,且返回所有Realm身份验证的认证信息,如果有一个失败就失败。

    而shiro的默认认证策略是AtLeastOneSuccessfulStrategy。

    还有其它两个认证策略:

    我想说:AtLeastOneSuccessfulStrategy为默认配置,AllSuccessfulStrategy配置也比较简单。

    但是在最新版本1.5.2版shiro中,FirstSuccessfulStrategy里新加了个属性,这个属性在shiro1.3.2中不存在。

    这个属性是——stopAfterFirstSuccess,(如果不是通过debug发现了这个属性,我到现在也不会得到正确结论)。

    shiro1.5.3源码:

    源码位置:shiro-root-1.5.2coresrcmainjavaorgapacheshiroauthcpam

    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.subject.PrincipalCollection;
    
    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 {
    
        private boolean stopAfterFirstSuccess;
    
        public void setStopAfterFirstSuccess (boolean stopAfterFirstSuccess ) {
    
            this.stopAfterFirstSuccess  = stopAfterFirstSuccess ;
        }
    
        public boolean getStopAfterFirstSuccess() {
            return stopAfterFirstSuccess ;
        }
    
        /**
         * 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;
        }
    
    
        /**
         * Throws ShortCircuitIterationException if stopAfterFirstSuccess is set and authentication is 
         * successful with a previously consulted realm. 
         * Returns the <code>aggregate</code> method argument, without modification
         * otherwise.
         */
        public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
            if (getStopAfterFirstSuccess() && aggregate != null && !isEmpty(aggregate.getPrincipals())) {
                throw new ShortCircuitIterationException();
            }
            return aggregate;
        }
    
        
    
        private static boolean isEmpty(PrincipalCollection pc) {
            return pc == null || pc.isEmpty();
        }
    
        /**
         * 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 && !isEmpty(aggregate.getPrincipals())) {
                return aggregate;
            }
            return info != null ? info : aggregate;
        }
    }

    再看看1.3.2源码:

    源码位置:shiro-root-1.3.2shirocoresrcmainjavaorgapacheshiroauthcpam

    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获得的真相

    之前的源码关联错了(关联1.3.2源码,而我导入的pom依赖是1.5.2,因此我怎么也找不到这个属性,后来不经意间想起来可能是源码的问题)

    不过当时虽然看不到这个属性,但我还是知道它存在,那么我是怎么知道有它呢?

    首先需写配置文件:

    shiro1.3.2在applicationContext.xml里配置多realm认证环境方式:(注:1.5.2版本如果这样配置的话,将无法获得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会是什么结果?

    结果就是:

    第一个realm即使验证通过,它还是会去验证第二个realm。

    也就是说,当前的配置和AtLeastOneSuccessfulStrategy配置效果一样,基本没有变化。

    可以看一下后台打印(两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-----没有异常!

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

    (注:我猜想这样设计的目的在于方便二者的切换,毕竟二者之间只相差这个属性)

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

  • 相关阅读:
    poj2356
    poj2021
    网络直销:贯通式电子商务营销
    网络营销趋同化时代到来
    一个睡五分钟等于六个钟头的方法
    张胜(帮别人名字作诗)
    我在阳光下向你表白
    李建逸(帮别人名字作诗)
    夜深,你的手机为谁而开
    杨英(帮别人名字作诗)
  • 原文地址:https://www.cnblogs.com/timingstarts/p/12779073.html
Copyright © 2020-2023  润新知