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中也可以看到。
所以先配置
authenticator
则
setAuthenticator()方法中realms属性为null
后配置
realms则
setRealms()的中会把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.
![](https://i-blog.csdnimg.cn/blog_migrate/8098bca24436a4c2ec92897771e54c07.png)