Shiro實戰(二)Shiro認證原理

在上篇Shiro核心概念中,咱們介紹了Shiro的三大核心概念:SubjectSecurityManagerRealms,並經過示例代碼QuickStart展現經常使用的認證、鑑權、退出的操做。數據庫

本篇咱們將深刻到Shiro的源碼中,探究Shiro底層實現認證的過程,作到「知其然知其因此然」。segmentfault

1 認證原理緩存

1.1 Principals與Credentialsui

認證就是進行身份確認的過程,也就是用戶(對應Shiro中的Subject)須要提供證實來證明本身的身份。就像到自動取款機取款,持有銀行卡的人就能夠理解爲此處的用戶,銀行卡的取款密碼就是證實材料,若是輸入正確的密碼,就能夠進行取款。在這個過程當中,有兩個概念,用戶和證實材料,對應Shiro中的就分別是Principals與Credentials。spa

1.2 認證步驟代理

要進行認證,咱們須要先收集用戶的Principals與Credentials,好比用戶經過頁面上的表單提交用戶名和密碼,APP用戶經過提交手機號與短信驗證碼,而後交由服務端進行處理。code

①服務端首先收集Principals與Credentials,對應Shiro的代碼對象

UsernamePasswordToken token = new UsernamePasswordToken("username", "passwd");

這裏咱們使用Shiro中經過的用戶名/密碼認證方式,或者你能夠實現AuthenticationToken接口來自定義blog

②接下來進行提交,對應代碼token

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

③認證結果

if (currentUser.isAuthenticated()) {
    // success do something
} else {
    // fail throw exception
}

1.3 認證原理

在瞭解了Shiro認證過程的基本代碼操做後,咱們來看下底層是到底如何實現。首先咱們先經過Shiro官方給出的一張認證流程圖來做全局的瞭解,看看底層認證都涉及到了哪些東西。
圖片描述

① 獲取Subject對象,若是還不瞭解如何獲取Subject對象,能夠回頭去看下咱們第一篇文章的介紹,或者下載示例代碼進行了解;而後收集用戶的認證資料,調用Subject對象的login(token)方法。

DelegatingSubject做爲Subject的實現,自己並不負責處理認證與受權的邏輯,而是將方法的調用傳遞給底層的SecurityManager,本質上說,DelegatingSubject只是SecurityManager的代理類,①中login(token)方法的調用,本質上調用調用的是SecurityManager接口的login(token)方法,而DefaultSecurityManager做爲SecurityManager的默認實現,將調用Authenticator進行認證邏輯處理

Authenticator接口是Shiro API中的主要入口之一,就是用來負責應用中的認證操做的,該類做爲頂級接口,只有一個authenticate(AuthenticationToken token)方法,而ModularRealmAuthenticator做爲Shiro默認的認證處理實現類將會接過認證處理的槍,經過doAuthenticate(AuthenticationToken token)來進行認證操做,源碼以下

Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
    return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
    return doMultiRealmAuthentication(realms, authenticationToken);
}

④ 經過狀況下應用中會使用單個的Realm來進行認證受權處理,可是強大的Shiro卻支持配置多個Realm,在多個Realm對象存在的狀況下,就須要指定認證策略AuthenticationStrategy ,Shiro提供了三種具體的認證策略實現

AtLeastOneSuccessfulStrategy:ModularRealmAuthenticator的默認實現,多個Realm中,若是有一個或以上認證經過,就表示認證成功
FirstSuccessfulStrategy:只使用第一個認證經過的Realm返回的信息,後面的Realm將會被忽略
AllSuccessfulStrategy:全部Realm認證經過纔算認證成功,不然認證失敗

⑤ 經過Realm進行認證最終的邏輯判斷,咱們此處以應用只存在單個Realm來進行介紹。Realm首先會經過realm.supports(token)進行驗證,驗證Realm是否支持對應的token進行認證操做,若是返回true,將會進行認證邏輯處理,不然直接忽略認證邏輯,若是咱們的應用只想處理受權,能夠自定義Realm,並將supports方法返回false便可。

Realm會經過token與INI配置文件中的配置項進行對比,或者與咱們數據庫存儲的數據進行對比,若是相同則認證經過。

下一小節,咱們將經過IniRealm來介紹Shiro是如何進行認證邏輯判斷的

1.4 IniRealm認證明現

在上篇文章中,咱們提到,Shiro默認使用IniRealm,可是前提是咱們在INI配置中指定了[users]或[roles]有效配置數據,不然就會用配置中指定的securityManager的realms,若是二者都沒有指定那麼就會拋出錯誤,由於Shiro應用,至少要配置一個Realm

IniRealm在初始化onInit()時,會將已經加載的INI文件中的[users]、[roles]配置進行處理,分別轉換爲SimpleRole、SimpleAccount,再將SimpleAccount與SimpleRole進行綁定,至此,IniRealm對INI配置文件處理已經完畢。

可是認證的操做並無完成,IniRealm仍須要與傳遞過來的token進行對比,判斷是否相同,具體的判斷邏輯交由AuthenticatingRealm來進行。

1.5 AuthenticatingRealm

AuthenticatingRealm是Realm的頂級抽象實現類,主要用於處理認證操做,至於受權等操做則交由該類的子類去處理。

AuthenticatingRealm拿到token後,會先去緩存中查找是否存在對應的認證信息,若是存在直接使用緩存中的認證信息與token進行比對,若是緩存中不存在,則直接獲取IniRealm中的認證信息進行比對,比對經過後,返回認證成功的Subject對象。

至此,認證的總體過程與底層邏輯已經所有介紹完畢。若是文章有什麼不足之處,或者說的不正確的地方,也但願各位小夥伴們與我聯繫和溝通。

相關文章
相關標籤/搜索