Apache Shiro 使用手冊(二)

認證就是驗證用戶身份的過程。在認證過程當中,用戶須要提交實體信息(Principals)和憑據信息(Credentials)以檢驗用戶是否合法。最多見的「實體/憑證」組合即是「用戶名/密碼」組合。

1、Shiro認證過程

一、收集實體/憑據信息
java

//Example using most common scenario of username/password pair:

UsernamePasswordToken token = new UsernamePasswordToken(username, password);

//」Remember Me」 built-in:

token.setRememberMe(true);
//Example using most common scenario of username/password pair:
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//」Remember Me」 built-in:
token.setRememberMe(true);

UsernamePasswordToken支持最多見的用戶名/密碼的認證機制。同時,因爲它實現了RememberMeAuthenticationToken接口,咱們能夠經過令牌設置「記住我」的功能。
可是,「已記住」和「已認證」是有區別的:
已記住的用戶僅僅是非匿名用戶,你能夠經過subject.getPrincipals()獲取用戶信息。可是它並不是是徹底認證經過的用戶,當你訪問須要認證用戶的功能時,你仍然須要從新提交認證信息。
這一區別能夠參考亞馬遜網站,網站會默認記住登陸的用戶,再次訪問網站時,對於非敏感的頁面功能,頁面上會顯示記住的用戶信息,可是當你訪問網站帳戶信息時仍然須要再次進行登陸認證。

二、提交實體/憑據信息
apache

Subject currentUser = SecurityUtils.getSubject();

currentUser.login(token);
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);

收集了實體/憑據信息以後,咱們能夠經過SecurityUtils工具類,獲取當前的用戶,而後經過調用login方法提交認證。

三、認證處理
session

try {

    currentUser.login(token);

} catch ( UnknownAccountException uae ) { ...

} catch ( IncorrectCredentialsException ice ) { ...

} catch ( LockedAccountException lae ) { ...

} catch ( ExcessiveAttemptsException eae ) { ...

} ... catch your own ...

} catch ( AuthenticationException ae ) {

    //unexpected error?

}
try {
    currentUser.login(token);
} catch ( UnknownAccountException uae ) { ...
} catch ( IncorrectCredentialsException ice ) { ...
} catch ( LockedAccountException lae ) { ...
} catch ( ExcessiveAttemptsException eae ) { ...
} ... catch your own ...
} catch ( AuthenticationException ae ) {
    //unexpected error?
}

若是login方法執行完畢且沒有拋出任何異常信息,那麼便認爲用戶認證經過。以後在應用程序任意地方調用SecurityUtils.getSubject() 均可以獲取到當前認證經過的用戶實例,使用subject.isAuthenticated()判斷用戶是否已驗證都將返回true.
相反,若是login方法執行過程當中拋出異常,那麼將認爲認證失敗。Shiro有着豐富的層次鮮明的異常類來描述認證失敗的緣由,如代碼示例。

2、登出操做
登出操做能夠經過調用subject.logout()來刪除你的登陸信息,如:
架構

currentUser.logout(); //removes all identifying information and invalidates their session too.
currentUser.logout(); //removes all identifying information and invalidates their session too.

當執行完登出操做後,Session信息將被清空,subject將被視做爲匿名用戶。

3、認證內部處理機制
以上,是Shiro認證在應用程序中的處理過程,下面將詳細解說Shiro認證的內部處理機制。


如上圖,咱們經過Shiro架構圖的認證部分,來講明Shiro認證內部的處理順序:
一、應用程序構建了一個終端用戶認證信息的AuthenticationToken 實例後,調用Subject.login方法。
二、Sbuject的實例一般是DelegatingSubject類(或子類)的實例對象,在認證開始時,會委託應用程序設置的securityManager實例調用securityManager.login(token)方法。
三、SecurityManager接受到token(令牌)信息後會委託內置的Authenticator的實例(一般都是ModularRealmAuthenticator類的實例)調用authenticator.authenticate(token). ModularRealmAuthenticator在認證過程當中會對設置的一個或多個Realm實例進行適配,它實際上爲Shiro提供了一個可拔插的認證機制。
四、若是在應用程序中配置了多個Realm,ModularRealmAuthenticator會根據配置的AuthenticationStrategy(認證策略)來進行多Realm的認證過程。在Realm被調用後,AuthenticationStrategy將對每個Realm的結果做出響應。
注:若是應用程序中僅配置了一個Realm,Realm將被直接調用而無需再配置認證策略。
五、判斷每個Realm是否支持提交的token,若是支持,Realm將調用getAuthenticationInfo(token); getAuthenticationInfo 方法就是實際認證處理,咱們經過覆蓋Realm的doGetAuthenticationInfo方法來編寫咱們自定義的認證處理。

4、使用多個Realm的處理機制:

一、Authenticator
默認實現是ModularRealmAuthenticator,它既支持單一Realm也支持多個Realm。若是僅配置了一個Realm,ModularRealmAuthenticator 會直接調用該Realm處理認證信息,若是配置了多個Realm,它會根據認證策略來適配Realm,找到合適的Realm執行認證信息。
自定義Authenticator的配置:
ide

[main]

...

authenticator = com.foo.bar.CustomAuthenticator

securityManager.authenticator = $authenticator
[main]
...
authenticator = com.foo.bar.CustomAuthenticator
securityManager.authenticator = $authenticator


二、AuthenticationStrategy(認證策略)
當應用程序配置了多個Realm時,ModularRealmAuthenticator將根據認證策略來判斷認證成功或是失敗。
例如,若是隻有一個Realm驗證成功,而其餘Realm驗證失敗,那麼此次認證是否成功呢?若是大多數的Realm驗證成功了,認證是否就認爲成功呢?或者,一個Realm驗證成功後,是否還須要判斷其餘Realm的結果?認證策略就是根據應用程序的須要對這些問題做出決斷。
認證策略是一個無狀態的組件,在認證過程當中會通過4次的調用:
工具

  • 在全部Realm被調用以前網站

  • 在調用Realm的getAuthenticationInfo 方法以前ui

  • 在調用Realm的getAuthenticationInfo 方法以後spa

  • 在全部Realm被調用以後code

認證策略的另一項工做就是聚合全部Realm的結果信息封裝至一個AuthenticationInfo實例中,並將此信息返回,以此做爲Subject的身份信息。
Shiro有3中認證策略的具體實現:

AtLeastOneSuccessfulStrategy 只要有一個(或更多)的Realm驗證成功,那麼認證將被視爲成功
FirstSuccessfulStrategy 第一個Realm驗證成功,總體認證將被視爲成功,且後續Realm將被忽略
AllSuccessfulStrategy 全部Realm成功,認證才視爲成功


ModularRealmAuthenticator 內置的認證策略默認實現是AtLeastOneSuccessfulStrategy 方式,由於這種方式也是被普遍使用的一種認證策略。固然,你也能夠經過配置文件定義你須要的策略,如:

[main]

...

authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy

securityManager.authenticator.authenticationStrategy = $authcStrategy

...
[main]
...
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
...


三、Realm的順序
由剛纔提到的認證策略,能夠看到Realm在ModularRealmAuthenticator 裏面的順序對認證是有影響的。
ModularRealmAuthenticator 會讀取配置在SecurityManager裏的Realm。當執行認證是,它會遍歷Realm集合,對全部支持提交的token的Realm調用getAuthenticationInfo 。
所以,若是Realm的順序對你使用的認證策略結果有影響,那麼你應該在配置文件中明肯定義Realm的順序,如:

blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm
securityManager.realms = $fooRealm, $barRealm, $blahRealm
相關文章
相關標籤/搜索