天天看點

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

權限管理 第2課 Shiro登入的源碼解析

權限管理 第1課 Shiro最簡demo

權限管理 第2課 Shiro登入的源碼解析

  我們上一課通過ini配置方式實作了最簡的shiro登入的操作,可是具體是怎麼實作操作的呢?我們在這一章通過debug方式看看shiro登入的實作原理

  我們仍舊基于上一課的代碼來作為例子。

1. 首先大體了解一下執行流程

  我們在剖析源碼之前先看一張圖,這張圖講述了Shiro登入過程中執行的流程:

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析
  1. 構造SecurityManager環境,就是上一課的通過SecurityManagerFactory建立SecurityManager對象,然後綁定到目前環境的操作;
    權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析
  2. Subject.login(),就是上一課中将

    token

    作為參數的登入的部分,這裡将是我們本次深度剖析的重點;
    權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析
  3. 剩下的步驟我們沒有在上一節課看到,我們這次來慢慢剖析。

2. 開始debug源碼

1.

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  我們首先把斷點點在

subject.login();

登入的方法這兒,開始

debug

執行,執行到斷點卡住的時候,我們點選

F7

進入看一下。

2.

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  首先我們看到這次我們跳轉到了DelegatingSubject類,這是Subject的一個實作類。

  1. 代碼停在了

this.clearRunAsIdentitiesInternal();

這個方法上,這個方法的作用是清除session中的已存在的登入資訊,我們既然是在登入,那麼就需要先将現在的登入狀态資訊清除掉;

  2. 我們點選

F8

執行到下一步,就是圖中紅色方框的位置。我們看到這裡調用了

this.securityManager

對象的

login()

方法,就如上面流程圖中的第3步,我們

Subject.login()

方法其實是調用

securityManager.login()

方法實作的登入操作;

  3. OK,我們繼續看一下

securityManager.login()

的實作原理吧,按

F7

進入

securityManager.login()

3.

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  我們看到代碼跳轉到了

DefaultSecurityManager

的類,是SecurityManager的實作類。我們先解析一下兩個對象:

  1.

AuthenticationInfo

存儲的是主體(Subject)的身份認證資訊,說白了是

realm

的身份資訊。

  2.

AuthenticationToken

用于收集使用者送出的身份(如使用者名)及憑據(如密碼),說白了是

Subject

傳入的身份資訊。

  3. 我們看到此時方法中調用了一個

this.authenticate();

的身份認證方法,我們按

F7

進入繼續探究。

4.

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  到了這一步我們可以看到,此刻方法調用了

authenticator

對象的

authenticate()

認證方法。Authenticator正是Shiro的身份認證器。

  也就是說一開始的

Subject.login()

調用了

SecurityManager.login()

方法,而

SecurityManager.login()

調用了

this.authenticate();

方法,而最終這個方法調用的是

Authenticator

的認證方法,繞了這麼一大圈,最後使用的還是

Authenticator

身份認證器進行認證登入的。

  但是之是以

Subject

不能直接調用

Authenticator

身份認證器是因為所有的主體的操作都應該由安全管理器

SecurityManager

進行統一管理,隻開放對

Subject

的API接口,這樣才能使程式更加安全。

  還沒完,我們繼續探究

Authenticator

身份認證器如何進行認證操作,我們按

F7

進入下一級。

5.

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  第70行,首先判斷token是否為空,為空的抛出異常

IllegalArgumentException

非法參數異常。

  第77行,調用了一個身份驗證的方法,我們進去看看,按

F8

下一步到這裡,然後按

F7

進入。

6.

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  嗯?這一步我們終于看到了Shiro三大要素之一的

Realm

  第107行,

this.assertRealmsConfigured();

是讀取資源配置,我們繼續往下執行,然後看一下reamls的資料:

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  哦?好熟悉的資料,好像是我們在

shiro.ini

配置的兩條參數。說明這裡已經把我們寫在配置檔案裡的模拟資料庫存儲的使用者的使用者名資訊讀取了出來。

  我們繼續,到109行,這個方法将

realms

清單和

Subject

輸入的

AuthenticationToken

的對象傳了進去進行對比,然後傳回對比的結果,看看是否存在和

Subject

傳入的使用者名相同的資料。這裡比較繞,說白了就是去

realms

清單裡找

Subject

輸入的使用者名是否存在,如果存在,傳回存儲的正确的使用者密碼。具體的我們

F7

進去看看。

7. 使用者不存在異常

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  首先判斷傳入的token是否支援realm,不支援抛異常

UnsupportedTokenException

,Token不支援異常;

  然後

realm.getAuthenticationInfo(token)

是用token的使用者名在realms裡尋找相同項,尋找到的話,傳回

realms

清單裡的那條資料,否則傳回

null

,這裡在下一步我們會詳細講解。

  再然後,開始判斷,傳回的

info

資料,如果是

null

的話,說明

Subject

輸入的使用者名不存在,此處抛出異常

UnknownAccountException

  是以我們之前在前一課的測試類裡捕獲登入抛出的這個異常時被定義為"使用者名不存在"的出處就在這裡。真的隐藏的好深是不是~~~

  那麼下面繼續執行,我上圖是使用者名不存在的執行到了這一步,下面我會切換成密碼不對,再執行一次,接着示範,是以下面的講解是基于使用者名存在的情況下。

8. 密碼不正确異常

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  此處我們假設使用者名是對的,那麼我們要在上一步的第59行進去,那麼就得到了本步驟的圖,如果此時使用者名是存在的,那麼第一個紅框中傳回的info是有資料的。那麼就執行到了第二個紅框,下圖就是進入第二個紅框的代碼:

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  此處我們在第218行進入看一眼,就是下圖代碼,代碼裡就已經很明确了,分别從

Subject

的token和

Realm

的info提取憑證對象,然後進行判斷,這裡就是最終的憑證(一般是密碼)之間的對比了,傳回 true/false。

權限管理 第2課 Shiro登入的源碼解析權限管理 第2課 Shiro登入的源碼解析

  那麼傳回上面第二圖的第218行,如果傳回的是false,那麼就抛出異常

IncorrectCredentialsException

,不正确憑證異常。

  我們之前在前一課的測試類裡捕獲登入抛出的這個異常時被定義為"密碼錯誤"的出處就在這裡。唉~ 心累~

9.

  剩下的就順理成章啦,如果賬号密碼都對的話,就是可以在

realms

裡找到使用者名,并且密碼也是比對正确的,就直接登入成功啦,至于

session

之類的東西,我們後面再說,本章就到這裡。

如果本文有錯誤或對本文有不了解的地方歡迎評論 ^_^

如果本文有幫助到您,可以點一下右上角的贊哦,謝謝啦