1.前提:前边学多realm的时候,使用一个认证器authenticator,同时该认证器会配置到securityManager的bean下,代码如下:
<bean id="securityManager"  class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="authenticator" ref="authenticator"/>
</bean>
<!-- 多realm认证器 -->
     <bean id="authenticator"  class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
           <property name="realms">
                <list>
                     <ref bean="jdbcRealm"/>
                     <ref bean="secondRealm"/>
                </list>
           </property>
           <!-- 修改认证策略 -->
           <property name="authenticationStrategy">
                <bean  class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"/>
           </property>
     </bean>
 
但是我们在做授权的时候需要从securityManager中获取realms,所以这里我们需要修改一下realms属性的配置代码如下:
<bean id="securityManager"  class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <--authenticator需要配置在realms之前-->
    <property name="authenticator" ref="authenticator"/>
    <property name="realms">
        <list>
            <ref bean="jdbcRealm"/>
            <ref bean="secondRealm"/>
        </list>
    </property>
</bean>
<!-- 多realm认证器 -->
<bean id="authenticator"  class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
    <!-- 修改认证策略 -->
    <property name="authenticationStrategy">
        <bean  class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"/>
    </property>
</bean>
 
 
这里有几个问题需要我们知道:
问题1:为什么要使用这种方式?
回答:因为授权时需要从securityManager中获取realms,所以一般使用此方式配置多realm
问题2:为什么这种方式使用没问题?
回答:参考问题3
问题3:实际调用是使用的是SecurityManager的realms,还是ModularRealmAuthenticator的realms?
回答:在自定义realm中打断点,当程序停下时向上翻到DefaultWebSecurityManager是可以看到,在SecurityManager认证时调用的是ModularRealmAuthenticator的authenticator()方法,需要用到realms的时候,调realms的是ModularRealmAuthenticator在IOC容器中注入时realms是配给SecurityManager的,而没有配给ModularRealmAuthenticator,但是为什么ModularRealmAuthenticator的realms会有值?原因就在于在启动项目时,AuthenticatingSecurityManager的afterRealmsSet()方法把SecurityManager的authenticator属性里面的值set到ModularRealmAuthenticator的realms里。
代码:((ModularRealmAuthenticator)authenticator).setRealms(getRealms());
简单的理解就是SecurityManager获取到(ModularRealmAuthenticator)authenticator属性和(Collection)realms属性,在SecurityManager的一个方法中(afterRealmsSet)再把realms放到(ModularRealmAuthenticator)authenticator的realms里
 
问题4:为什么authenticator属性要配置在realms之前?
回答:因为这涉及是先setAuthenticator()还是setRealms()的问题,
正常应该先setAuthenticator()setRealms(),这是因为setAuthenticator()方法注入的是上面配置的多realm认证器,在IOC容器中我们可以看到此时realms已经不在这里配置了,所以ModularRealmAuthenticator的realms属性为null,下面代码debug中也可以看到。
所以先配置authenticatorsetAuthenticator()方法中realms属性为null
后配置realmssetRealms()的中会把realms属性设置回来。
如果配置相反,则配置了realms属性之后,setAuthenticator()方法中又把realms属性置为null
因此导致异常:
java.lang.IllegalStateException: Configuration error:  No realms have been configured!  One or more realms must be present to execute an authentication attempt.
6.Shiro授权_前提

相关文章: