注:該系列所有測試均在之前建立的Shiro3的Web工程的基礎上。
上一篇我們講到了Shiro的多Realm驗證,并且編寫執行個體進行了測試。對于多Realm校驗,我們還需要知道,兩個Realm時,怎麼才能知道認證通過了?是一個Realm通過了就通過,還是全部Realm通過了才通過,還是其它?這就牽扯到了認證政策。
認證政策實際上是AuthenticationStrategy這個接口,它有三個實作:
(1) FirstSuccessfulStrategy:隻要有一個Realm驗證成功即可,隻傳回第一個Realm身份驗證成功的認證
資訊,其他的忽略。
(2) AtLeatOneSuccessfulStrategy:隻要有一個Realm驗證成功即可,和FirstSuccessfulStrategy不同,将
傳回所有Realm身份校驗成功的認證資訊。
(3) AllSuccessfulStrategy:所有Realm驗證成功才算成功,且傳回所有Realm身份認證成功的認證資訊,如
果有一個失敗就失敗了。
我們之前使用的ModularRealmAuthenticator預設是AtLeatOneSuccessfulStrategy。
我們再回顧一下ModularRealmAuthenticator的源碼:
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
assertRealmsConfigured();
Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
return doMultiRealmAuthentication(realms, authenticationToken);
}
}
多Realm校驗會走下面的doMultiRealmAuthentication方法,其源碼如下:
protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
AuthenticationStrategy strategy = getAuthenticationStrategy();
AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
if (log.isTraceEnabled()) {
log.trace("Iterating through {} realms for PAM authentication", realms.size());
}
for (Realm realm : realms) {
aggregate = strategy.beforeAttempt(realm, token, aggregate);
if (realm.supports(token)) {
log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);
AuthenticationInfo info = null;
Throwable t = null;
try {
info = realm.getAuthenticationInfo(token);
} catch (Throwable throwable) {
t = throwable;
if (log.isDebugEnabled()) {
String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";
log.debug(msg, t);
}
}
aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
} else {
log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token);
}
}
aggregate = strategy.afterAllAttempts(token, aggregate);
return aggregate;
}
在上面的源碼中,我們可以看到方法首先調用getAuthenticationStrategy()方法擷取了一個認證政策類,而在方法的最後又
獲得了一個AuthenticationInfo認證消息。
為了看到使用ModularRealmAuthenticator最後獲得的認證消息,我們将之前Shiro3工程的SecordRealm的代碼做一些更改:
SimpleAuthenticationInfo info = null;
info = new SimpleAuthenticationInfo("SecondRealmName", credentials, credentialsSalt, realmName);
return info;
将第二個Realm的認證結果中的賬号改為“SecondRealmName”。原來在我們的Shiro3工程中,ShiroRealm和SecordRealm中
都沒有admin賬戶,我們這裡僅為SecordRealm添加一個admin賬戶,作為後面的測試區分:
userMap.put("admin", new User("admin","463c6a4b033daaee524da5cb3a5562a5f3feeaa7",false));//密碼明文:aabbcc
然後使用admin進行登入:

在doMultiRealmAuthentication的源碼處打斷點,首先可以發現的是getAuthenticationStrategy方法拿到的政策:
可以看到就是AtLeatOneSuccessfulStrategy政策。代碼走到最後,我們可以看到傳回的認證資訊:
可以看到包含了兩個Realm最後傳回的認證資訊,這就說明符合AtLeatOneSuccessfulStrategy政策的原則,隻要有一個
Realm校驗通過就通過,并且傳回所有Realm的認證資訊。
如果我們想要更換認證政策,則需要在IOC容器的配置檔案applicationContext.xml中為之前配置的認證器添加一個
authenticationStrategy參數:
<!-- 認證器 -->
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<property name="realms">
<list>
<ref bean="shiroRealm"/>
<ref bean="secordRealm"/>
</list>
</property>
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>
</property>
</bean>
我們上面将認證政策更改為AllSuccessfulStrategy,即所有Realm驗證成功才算成功。
我們進行測試,使用admin進行登入,發現登入失敗:
這是因為我們的兩個Realm中,隻有第二個Realm包含admin的認證資訊,是以第一個Realm認證失敗,第二個Realm認證成功,
而根據政策,所有Realm驗證成功才算成功,是以但凡有一個Realm校驗失敗,本次校驗都是失敗的,剩餘的Realm也無需執行。
轉載請注明出處:http://blog.csdn.net/acmman/article/details/78636970