將 Shiro 做爲應用的權限基礎

    Shiro 是 Java 世界中新近出現的權限框架,較之 JAAS 和 Spring Security,Shiro 在保持強大功能的同時,還在簡單性和靈活性方面擁有巨大優點。本文介紹了 Shiro 的關鍵概念和權限模型,同時給出了 Shiro 以及 Grails Shiro Plugin 的使用示例。在閱讀本文的過程當中,讀者能夠充分的體會到 Shiro 的魅力。web

前言數據庫

    Shiro 是 JAVA 世界中新近出現的權限框架,較之 JAAS 和 Spring Security,Shiro 在保持強大功能的同時,還在簡單性和靈活性方面擁有巨大優點。本文就帶領讀者一睹 Shiro 的風采。緩存

    可能你們早先會見過 J-security,這個是 Shiro 的前身。在 2009 年 3 月初以前,這個安全框架叫作 J-security,因爲某些緣由,改名爲 Shiro(或者 Ki,意爲 Fortress),是 Apache 的孵化項目,鑑於本文編寫時 Shiro 的尚未正式發佈的版本,本文使用的是 Jsecurity 的穩定版本 0.9,本文中 Shiro 等同於 Jsecurity。安全

    本文將涉及 Shiro 的總體框架、安全模型、關鍵概念類,同時給出了 Shiro 以及 Grails Shiro Plugin 的使用示例,能夠下載文中使用的源代碼。服務器

本文代碼的開發環境:session

  • Jsecurity 0.9架構

  • Grails 1.2.0框架

  • Grails Shiro Plugin 1.0.1ide

  • SpringSource Tool Suite 2.3工具

    Shiro 是一個強大而靈活的開源安全框架,可以很是清晰的處理認證、受權、管理會話以及密碼加密。以下是它所具備的特色:

  • 易於理解的 Java Security API;

  • 簡單的身份認證(登陸),支持多種數據源(LDAP,JDBC,Kerberos,ActiveDirectory 等);

  • 對角色的簡單的籤權(訪問控制),支持細粒度的籤權;

  • 支持一級緩存,以提高應用程序的性能;

  • 內置的基於 POJO 企業會話管理,適用於 Web 以及非 Web 的環境;

  • 異構客戶端會話訪問;

  • 很是簡單的加密 API;

  • 不跟任何的框架或者容器捆綁,能夠獨立運行。

目前還有其餘出現較早的安全框架,好比 JAAS,Spring Security。

    JAAS —面世的時間最先,可是鑑於其在使用上有很大的限制,不多有人真正的使用它。能夠說它不是一個好的應用程序級別的安全框架;

    Spring Security —目前是 Java 安全框架領域當之無愧的老大,已經很是成熟了;若是使用 Spring 框架,能夠首選 Spring Security,可是對於單應用來講,Shiro 更顯簡單方便。

下面就開始咱們的 Shiro 之旅吧!

總體架構

首先,咱們來看看的 Shiro 的總體架構,見下圖:

圖 1. 總體架構

從上圖能夠看出,Shiro主要有四個組件:

一、SecurityManager

    典型的Facade,Shiro經過它對外提供安全管理的各類服務。

二、Authenticator

    對"Who are you"實現覈實。一般涉及用戶名和密碼。

    這個組件負責收集principals和credentials,並將它們提交給應用系統。吐過提交的credentials跟應用系統中提供的credentials溫和,就能繼續訪問,不然須要從新提交principals和credentials,或者終止訪問。

三、Authorizer

    身份驗證經過後,由這個組件對登錄人員進行訪問控制的篩查,好比"Who can do what",或者"Who can 都 which action"。Shiro採用基於Realm的方法,即用戶(又稱爲Subject)、用戶組、角色和permission的聚合體。

四、SessionManager

    這個組件保證了異構客戶端的訪問,配置簡單,它是基於POJO/J2SE的,不跟任何的客戶端或者協議綁定。

    Shiro的認證和簽證能夠經過JDBC、LDAP 或者 Active Directory 來訪問數據庫、目錄服務器或者 Active Directory 中的人員以及認證 / 籤權信息。SessionManager 經過會話 DAO 能夠將會話保存在 cache 中,或者固化到數據庫或文件系統中。

安全模型

從Shiro的框架圖,已經可以體會到這個工具的簡單。下面讓咱們看看Shiro是如何工做的。

圖 2. 安全模型

上圖,設計了Shiro的五個概念:

一、Subject是安全領域的術語,除了表明人,他還能夠是應用。在單應用中,可將其設爲User的同義詞。

二、Principle是Subject的標識,通常狀況下是惟一的標識,好比用戶名。

三、Role和Permission分別表明了不一樣粒度的權限,從上圖能夠看出Role的粒度更大些,Permission表明了系統的原子權限,好比數據的修改、刪除權限。對於簡單的權限應用,能夠不須要Permission。

四、Realm是一個執行者,負責真正的認證和鑑權。

實現應用的安全模式的關鍵在於:定義合適的role和permission,這就須要遵循以下原則:

一、role沒有實質內容,只是表明了一種permission,目的是爲了管理的方便,通常都是動態定義;

二、permission通常都是預先定義好的,不容許動態改變,除非源碼改動,它纔會變化,它是整個安全模塊的基礎;

三、要是permission也能動態定義,並不是不可能,可是這將鑑權很是複雜,甚至可能致使鑑權語句遍及整個程序,得不償失;

四、固然有一個例外的:若是知道permission動態定義的規則和鑑權規則,如Grail的filter中「${controllerName}:${actionName}:${params.id}」也可實現permission的動態定義。

關鍵概念類

·理解 Shiro 的架構和安全模型了,咱們來看看更具體些的內容。下圖顯示了 Shiro 中的關鍵概念類(參考資料 -- JSecurity Mini Guide)。

圖 3. 關鍵類

AuthenticationToken 和 AuthenticationInfo

前者在認證前使用,描述認證所需的信息,最經常使用的就是 username 和 password 對;後者在認證後使用,內容同前,可是表示已經通過認證的信息。

RememberMe

表明的是一種可能狀態,並不表示該 Subject 已經通過了認證。對於一些普通的操做,這種可能狀態並沒有大礙,但一旦涉及安全敏感的操做,必須通過認證。

Credentials 和 CredentialsMatcher

Credentials 是 Subject 的證書,在認證時使用,最經常使用的就是 password。在一般狀況下,爲了安全起見,Subject 的 credentials 都須要加密保存,因而 CredentialsMatcher 的做用就體現出來了,見下圖:

圖 4. CredentialsMatcher 的做用

這裏 CredentialsMatcher 須要將加密後的證書跟用戶登陸時提供的證書進行比對,完成認證的過程。

PAM= Pluggable Authentication Modules

在有多個 Realm 的時候使用。由認證策略決定認證結果,即 PAM= Relams + 認證策略。通常的策略有 3 種:AllSuccessful、AtLeastOneSuccessful 和 FirstSuccessful。

AuthorizationInfo

能夠當作是 Role + Permission 的組合體。

PermissionResolver 和 Permission

它們之間的關係以下:

圖 5. PermissionResolver 和 Permission 的關係

    在 Shiro 中,權限被轉化爲一種字符串描述(字符串分級表示,稱之爲 WildcardPermission),從而將權限轉化爲相似於對象 equals 的操做(Shiro 中的 implies 方法)。

內置的權限有 2 個:

  • AllPermission,老是返回 true

  • WildcardPermission,權限字符串的表示方式。

    這裏重點聲明一下。WildcardPermission 是 Shiro 的精妙之處,咱們能夠將權限表示成字符串,這樣對權限的控制能夠不拘泥於物理存儲,好比對 messagge 類具備修改和刪除權限能夠標識爲:message:update,delete:*,其中‘ * ’表示全部;第一級分隔符爲‘ : ’;第二級分隔符爲‘ , ’,而對於權限字符串的解釋徹底能夠由應用本身來定。

    若是要比較權限字符串,可使用 permission1.implies(permission2),它分別比較對應位置的字符串,在以下狀況中,結果會返回 true:

  • permission1 中的子串有 * 或 permission1 子串 ==permission2 子串;

  • permission1 無子串,permission2 有;

  • permission1 有子串,permission2 無,permission1 的全部子串都是 *。

總的說來,Shiro 中的 Permission 須要注意以下內容:

  • 權限的比較實際是字符串的比較,只不過是考慮到了字符串的分級

  • 字符串的分級劃分徹底由使用者本身決定,Shiro 的慣例是 3 級:資源 : 操做 : 實例。

  • 字符串的使用必須一致,分隔符之間不要有空格,避免無心間引入的不一致。如:定義使用「file : create, update : 1」,而驗證使用「file : update」,那麼分解以後一個是「 update 」,一個是「 update」,因空格而引發不等。

Realm

    這是一個實際訪問安全實體的組件,通常是應用相關的,跟數據源的關係是 1-1。它負責完成認證和鑑權,getAuthenticationInfo 表明了 login 的嘗試,鑑權方法則由 Authorizer 繼承而來。此處也體現了 Shiro 代碼的另外一個特色,經過繼承來擴充功能。以經常使用的 JdbcRealm 爲例,其繼承鏈以下:

圖 6. JdbcRealm 的繼承鏈

Session

    它關聯一個 Subject 的上下文,其做用相似於在 HttpSession 中保存用戶標識,session 一旦過時,則從新登陸。Shiro 的 Session 是獨立的,其目的是作到環境無關性。爲了利用 Web 環境中,Shiro 實現了一個直接使用 HttpSession 的 WebSession。

SecurityManager

    這是一個 Façade 接口,=Authenticator + Authorizer + SessionFactory。在總體框架圖中已經看到了它在 Shiro 中所處的位置。其特色同 Realm,同樣是使用繼承不斷地擴充功能。對於 Web 應用通常使用 DefaultWebSecurityManager。

Filter

    在 Web 環境下使用 filter 進行認證和權限檢查是毋庸置疑的,而 Shiro 的特色則在於由一個主 Filter 將一羣子 filter 串起來:

圖 7. Filter 的做用

在實際使用時,須注意:

一、web.xml 中只需配置 JSecurityFilter。對於 Spring 應用,則使用 SpringJSecurityFilter;

二、子 filter 做爲主 filter 的配置參數值出現,特色是:順序相關

  • 對於多個 URL,驗證順序是由上至下,相似 Exception 的匹配。所以,使用順序應該是由細到粗。

  • 對於同一 URL,子 filter 的驗證順序是從左至右的 AND 操做。

三、若是配置值中含有分隔符,如 Permission,就須要使用引號來轉義

Subject

    subject 表明了一個用戶的狀態和操做,它提供了全部安全相關的操做,包括認證和籤權。能夠將其視爲另外一種形式的 Façade。缺省實現是將這些操做委派給其內部包含的 SecurityManager。

Configuration

    configuration 負責將全部這些組件串起來,最終建立 SecurityManager。在 Shiro 中,缺省格式是 ini。整個配置關係以下圖:

圖 8. 配置關係

其中:

    JSecurityFilter 建立 Configuration 實例,並將 ini 參數值傳給 Configuation。在 Spring 環境中,分別使用 SpringJSecurityFilter 和 SpringIniWebConfiguration。

    Configuration 實際就是 SecurityManager 的 Factroy,對 SpringIniWebConfiguration 而言,它須要知道 SecurityManager 的 BeanName,該值由 SpringJSecurityFilter 的初始化參數「securityManagerBeanName」值決定。即 SpringJSecurityFilter,實際有兩個初始化參數:

    config,是 ini 配置文件內容

    securityManagerBeanName,是 SecurityManager 的 BeanName

SecurityUtils

這是 Shiro 中最重要的工具類,由它能夠方便地得到 Subject 和 SecurityManager。

雜項

  • AOP,提供 AOP 方面的支持,實現對某個類某個方法的攔截,從而使權限控制延伸至類的方法。

  • Cache,提供緩存支持

  • Codec,提供編碼方面的支持

  • Crypto,提供加密支持

  • IO,從多個資源位置讀寫原始數據

  • JNDI,提供 jndi 支持

  • util,工具類支持

  • 標籤類,用於 Web 頁面

注:原文還有基於groovy的例子,在此沒有轉載。

相關文章
相關標籤/搜索