1. 程式人生 > >shiro實戰系列(七)之Realm

shiro實戰系列(七)之Realm

這一 憑證 類型 自由 單向 徹底 res arr jpa

Realm 是一個能夠訪問應用程序特定的安全數據(如用戶、角色及權限)的組件。Realm 將應用程序特定的數據轉 換成一種 Shiro 能夠理解的格式,這樣 Shiro 能夠提供一個單一的易理解的 Subject 編程 API,無論有多少數據源存在 或你應用程序特定的數據是怎樣的。 Realm 通常和數據源是一對一的對應關系,如關系數據庫,LDAP 目錄,文件系統,或其他類似資源。因此,Realm 接口的實現使用數據源特定的 API 來展示授權數據(角色,權限等),如 JDBC,文件 IO,Hibernate 或 JPA,或其他 數據訪問 API。

Realm 實質上就是一個特定安全的 DAO 因為這些數據源大多通常存儲身份驗證數據(如密碼的憑證)以及授權數據(如角色或權限),每個 Shiro Realm 能夠執行身份驗證和授權操作。

(1)Realm configuration

如果使用 Shiro 的 INI 配置文件,你能夠自定義及引用 Realm,就像在[main]項中的任何其他對象一樣,但它們在 securityManager 中采用兩種方法之一進行配置:顯式或隱式。

(2)Explicit Assignment

基於迄今的 INI 配置知識,這是一個顯示的配置方法。在定義一個或多個 Realm 後,你將它們作為 securityManager 對象的集合屬性

技術分享圖片

顯式分配是確定的——你控制具體使用哪一個 Realm 及它們用於身份驗證和授權的順序。Realm 順序的作用在 Authentication 章的 Authentication Sequence 節進行了詳細的介紹。

(3) Implicit Assignment

Not Preferred(不推薦)

這種方法可能引發意想不到的行為,如果你改變 realm 定義的順序的話。建議你避免使用此方法,並使用顯式分配, 它擁有確定的行為。該功能很可能在未來的 Shiro 版本中被廢棄或移除。 如果出於某些原因你不想顯式地配置 securityManager.realms 的屬性,你可以允許 Shiro 檢測所有配置好的 realm 並直接將它們指派給 securityManager。 使用這種方法,realm 將會按照它們預先定義好的順序來指派給 securityManager 實例。 也就是說,對於下面的 shiro.ini 示例:

blahRealm = com.company.blah.Realm

fooRealm = com.company.foo.Realm

barRealm = com.company.another.Realm

# no securityManager.realms assignment here

基本上和下面這一行具有相同的效果:

securityManager.realms = $blahRealm, $fooRealm, $barRealm

然而,實現隱式分配,只是 realm 定義的順序直接影響到了它們在身份驗證和授權嘗試中的訪問順序。如果你改變 它們定義的順序,你將改變主要的 Authenticaor 的 Authentication Sequence 是如何起作用的。 由於這個原因,以及保證明確的行為,我們推薦使用顯式分配而不是隱式分配。

(3) Realm Authentication

當你理解了 Shiro 的主要 Authentication 工作流後,了解在一個授權嘗試中當 Authenticator 與 Realm 交互時到底發 生了什麽是很重要的。

a.Supporting AuthenticationTokens

在 authentication sequence 中已經提到,當在 Realm 被訪問來執行一個授權嘗試之前,它的supports 方法被調用。 如果返回值為 true,則只有這樣它的 getAuthenticationInfo(token)方法才會被調用。 通常 realm 會檢查提交的 token 的類型(接口或類)來判斷它是否能夠處理它。

例如,一個能夠處理生物數據的 realm 可能就一點也不理解 UsernamePasswordTokens,這樣它將從 supports 方法返回 false。

b.Handling supported AuthenticationTokens

若 Realm 支持一個提交的 AuthenticationToken,那麽 Authenticator 將會調用該 Realm 的 getAuthenticationInfo(token) 方法。這有效地代表了一個與 Realm 的後備數據源的授權嘗試。該方法按以下方法進行:

1. 為主要的識別信息(帳戶識別信息)檢查 token。

2. 基於 principal 在數據源中尋找相吻合的帳戶數據。

3. 確保 token 支持的 credentials 匹配那些存儲在數據源的。

4. 若 credentials 匹配,返回一個封裝了 Shiro 能夠理解的帳戶數據格式的 AuthenticationInfo 實例。

5. 若 credentials 不匹配,則拋出 AuthenticationException 異常。

這是對所有 Realm getAuthenticationInfo 實現的最高級別的工作流。在此方法中,Realm 可以自由地做任何它們想做 的,如記錄在審計日誌的嘗試,更新數據記錄,或任何其他可以對該數據存儲的身份驗證嘗試有意義的東西。 唯一需要的東西就是,如果 credentials 匹配給予的 principal(s),那麽返回一個非空的 AuthenticationInfo 實例來代表 來自於該數據源的 Subject 帳戶信息。

c.Save Time

直接實現 Realm 接口可能導致時間消耗及錯誤。大多數人們選擇 AuthorizingRealm 抽象類的子類而不是從頭開始。 這個類實現了常用的 authentication 及 authorization 工作流來節省你的時間和精力。

d.Credentials Matching

在上面的 realmauthentication 工作流中,Realm 不得不驗證 Subject 提交的 credentials(如,,密碼)必須匹配存儲 在數據存儲中的 credentials。如果匹配,則被認為身份驗證成功,同時系統還必須驗證終端用戶的身份。 Realm Credentials Matching 這是每個 Realm 的責任,去匹配提交的 credentials 和那些存儲在 Realm 後備數據存儲中的 credentials,而不是 Authenticator 的責任。每個 Realm 擁有有關私人信息的 credentials 格式,存儲及能夠執行詳細的 credentials 匹配, 然而 Authenticator 只是一個普通的工作量組件。

credentials 的匹配過程在所有應用程序中幾乎一樣,通常不一樣的是進行比較的數據。為了確保該過程是可插入及 可定制的如果需要的話,AuthenticatingRealm 及它的子類支持 CredentialsMatcher 來執行 credentials 對比的概念。 在發現帳戶數據後,它以及提交的 AuthenticationToken 用來代表一個 CredentialsMatcher 來判斷所提交的是否匹配 所存儲的。 Shiro 擁有某些可以讓你立即使用的 CredentialsMatcher 實現,如 SimpleCredenticalsMatcher 和 HashedCredentialsMatcher,但如果你想為自定義的邏輯配置一個自定義的實現,你可以像下面一樣直接做:

技術分享圖片

e.Simple Equality Check

所有 Shiro 立即可用的 Realm 的實現默認使用 SimpleCredentialsMatcher。SimpleCredentialsMatcher 執行一個普通的 直接平等檢查,關於存儲的帳戶 credentials 與在 AuthenticationToken 所提交的之間的檢查。

例如,若一個 UsernamePasswordToken 被提交後,則 SimpleCredentialsMatcher 驗證該密碼實際上是否與存儲在數 據庫中的密碼相同。 SimpleCredentialsMatcher 不僅僅為字符串執行直接相等比較。它能夠處理大多數常用的字節碼,像字符串,字符數 組,字節數組,文件及輸入流。請參考它的 JavaDoc 獲取更多。

f.Hashing Credentials

並非是存儲credentials 在其原始的 form 及執行原始/普通的比較,一個更安全的方式存儲終端用戶的credentials(如, 密碼)是在存儲它們到數據存儲之前將它們單向散列化。 這確保終端用戶的 credentials 絕不會以原始的 form 存儲,而且沒人會知道原始值。這是一個比純文本或原始比較 更為安全的機制,同時所有關註安全的應用程序應該較非哈希化的存儲更為喜歡。 為了支持這些首選的加密哈希策略,Shiro 提供了 HashedCredentialsMatcher 的實現配置在 realm 上而不是上述 SimpleCredentialsMatcher。 哈希 credentials 及 salting 和多個哈希叠代的好處超出了該 Realm 文檔的範圍,但絕對要閱讀 HashedCredentialsMatcher 的 JavaDoc,其中將詳細介紹這些細節。

g.Hashing and Corresponding Matchers

那麽,你如何很容易地配置一個啟用 Shiro 的應用程序呢? Shiro 提供了多個 HashedCredentialsMatcher 子類實現。你必須在你的 realm 中配置指定的實現來匹配你 hash 化你用 戶 credentials 時使用的哈希算法。

例如,假設你的應用程序為身份驗證使用用戶名/密碼對。由於上文所述的哈希憑據的好處,假設當你創建一個用 戶帳戶時,你想使用 SHA-256 算法單向散列用戶的密碼。你將哈希用戶輸入的純文本密碼並保持該值:

技術分享圖片

既然你使用 SHA-256 散列你用戶的密碼,你需要告訴 Shiro 使用合適的 HashedCredentialsMatcher 以匹配你的哈希參 數選擇。在這個例子中,我們創建了一個隨機的 salt 並執行 1024 次哈希叠代,為了強大的安全性(請參見 HashedCredentialsMatcher 的 JavaDoc 獲取原因)。這裏是完成這項工作的 Shiro INI 配置:

技術分享圖片

h.SaltedAuthenticationInfo

為了確保這一工程,最後要做的事情是,你的 Realm 實現必須返回一個 SaltedAuthenticationInfo 實例而不是一個普 通的 AuthenticationInfo 實例。SaltedAuthenticationInfo 接口確保在你創建用戶帳戶(如,user.setPasswordSalt(Salt); call above)時使用的 salt 能夠被 HashedCredentialsMatcher 引用. HashedCredentialsMatcher 需要該 salt 為了能夠在提交的 AuthenticationToken 上執行相同的哈希技術來判斷該 token 是否匹配你保存在數據存儲中的東西。因此,如果你為用戶密碼使用 salting(而且你應該這樣做!!!),確保你 的 Realm 實現能夠通過返回的 SaltedAuthenticationInfo 實例代表密碼。

i.Disabling Authentication

如果出於某些原因,你不想用 Realm 對數據源執行身份驗證(也許是由於你只想 Realm 執行授權),你可以徹底地 禁用 Realm 對身份驗證的支持通過從 Realm 的 support 方法返回 false。然後你的 realm 在身份驗證嘗試中永遠不會 被訪問到。 當然,至少需要一個能夠支持 AuthenticationTokens 且已配置的 Realm,如果你想驗證 Subjects

shiro實戰系列(七)之Realm