天天看點

【Shiro權限管理】12.Shiro認證政策

注:該系列所有測試均在之前建立的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進行登入:

【Shiro權限管理】12.Shiro認證政策

在doMultiRealmAuthentication的源碼處打斷點,首先可以發現的是getAuthenticationStrategy方法拿到的政策:

【Shiro權限管理】12.Shiro認證政策

可以看到就是AtLeatOneSuccessfulStrategy政策。代碼走到最後,我們可以看到傳回的認證資訊:

【Shiro權限管理】12.Shiro認證政策

可以看到包含了兩個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進行登入,發現登入失敗:

【Shiro權限管理】12.Shiro認證政策
【Shiro權限管理】12.Shiro認證政策

這是因為我們的兩個Realm中,隻有第二個Realm包含admin的認證資訊,是以第一個Realm認證失敗,第二個Realm認證成功,

而根據政策,所有Realm驗證成功才算成功,是以但凡有一個Realm校驗失敗,本次校驗都是失敗的,剩餘的Realm也無需執行。

轉載請注明出處:http://blog.csdn.net/acmman/article/details/78636970

繼續閱讀