分散式中的HS(HighSecurity) --Subject,SecuratyManager,Realms

weixin_33860553發表於2012-06-01

誰在用Shiro?

  Shiro及其前身JSecurity已被各種規模和不同行業的公司專案採用多年。自從成為Apache軟體基金會的頂級專案後,站點流量和使用呈持續增長態勢。許多開源社群也正在用Shiro,這裡有些例子如Spring,Grails,Wicket,Tapestry,Tynamo,Mule和Vaadin。

  如Katasoft,Sonatype,MuleSoft這樣的商業公司,一家大型社交網路和多家紐約商業銀行都在使用Shiro來保護他們的商業軟體和站點。

  核心概念:Subject,SecurityManager和Realms

  既然已經描述了Shiro的好處,那就讓我們看看它的API,好讓你能夠有個感性認識。Shiro架構有三個主要概念 - Subject,SecurityManager和Realms。

  Subject

  在考慮應用安全時,你最常問的問題可能是“當前使用者是誰?”或“當前使用者允許做X嗎?”。當我們寫程式碼或設計使用者介面時,問自己這些問題很平常:應用通常都是基於使用者故事構建的,並且你希望功能描述(和安全)是基於每個使用者的。所以,對於我們而言,考慮應用安全的最自然方式就是基於當前使用者。Shiro的API用它的Subject概念從根本上體現了這種思考方式。

  Subject一詞是一個安全術語,其基本意思是“當前的操作使用者”。稱之為“使用者”並不準確,因為“使用者”一詞通常跟人相關。在安全領域,術語“Subject”可以是人,也可以是第三方程式、後臺帳戶(Daemon Account)或其他類似事物。它僅僅意味著“當前跟軟體互動的東西”。但考慮到大多數目的和用途,你可以把它認為是Shiro的“使用者”概念。在程式碼的任何地方,你都能輕易的獲得Shiro Subject,參見如下程式碼:

  清單1. 獲得Subject

import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
...
Subject currentUser = SecurityUtils.getSubject();

 

  一旦獲得Subject,你就可以立即獲得你希望用Shiro為當前使用者做的90%的事情,如登入、登出、訪問會話、執行授權檢查等 - 稍後還會看到更多。這裡的關鍵點是Shiro的API非常直觀,因為它反映了開發者以‘每個使用者’思考安全控制的自然趨勢。同時,在程式碼的任何地方都能很輕鬆地訪問Subject,允許在任何需要的地方進行安全操作。

  SecurityManager

  Subject的“幕後”推手是SecurityManager。Subject代表了當前使用者的安全操作,SecurityManager則管理所有使用者的安全操作。它是Shiro框架的核心,充當“保護傘”,引用了多個內部巢狀安全元件,它們形成了物件圖。但是,一旦SecurityManager及其內部物件圖配置好,它就會退居幕後,應用開發人員幾乎把他們的所有時間都花在Subject API呼叫上。

  那麼,如何設定SecurityManager呢?嗯,這要看應用的環境。例如,Web應用通常會在Web.xml中指定一個Shiro Servlet Filter,這會建立SecurityManager例項,如果你執行的是一個獨立應用,你需要用其他配置方式,但有很多配置選項。

  一個應用幾乎總是隻有一個SecurityManager例項。它實際是應用的Singleton(儘管不必是一個靜態Singleton)。跟Shiro裡的幾乎所有元件一樣,SecurityManager的預設實現是POJO,而且可用POJO相容的任何配置機制進行配置 - 普通的Java程式碼、Spring XML、YAML、.properties和.ini檔案等。基本來講,能夠例項化類和呼叫JavaBean相容方法的任何配置形式都可使用。

  為此,Shiro藉助基於文字的INI配置提供了一個預設的“公共”解決方案。INI易於閱讀、使用簡單並且需要極少依賴。你還能看到,只要簡單地理解物件導航,INI可被有效地用於配置像SecurityManager那樣簡單的物件圖。注意,Shiro還支援Spring XML配置及其他方式,但這裡只我們只討論INI.

    

下列清單2列出了基於INI的Shiro最簡配置:

  清單2. 用INI配置Shiro

[main]
cm = org.apache.shiro.authc.credential.HashedCredentialsMatcher
cm.hashAlgorithm = SHA-512
cm.hashIterations = 1024
# Base64 encoding (less text):
cm.storedCredentialsHexEncoded = false
iniRealm.credentialsMatcher = $cm
[users] 
jdoe = TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJpcyByZWFzb2 
asmith = IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbXNoZWQsIG5vdCB

  在清單2中,我們看到了用於配置SecurityManager例項的INI配置例子。有兩個INI段落:[main]和[users].

  [main]段落是配置SecurityManager物件及其使用的其他任何物件(如Realms)的地方。在示例中,我們看到配置了兩個物件:

  cm物件,是Shiro的HashedCredentialsMatcher類例項。如你所見,cm例項的各屬性是通過“巢狀點”語法進行配置的 - 在清單3中可以看到IniSecurityManagerFactory使用的慣例,這種方法代表了物件圖導航和屬性設定。

  iniRealm物件,它被SecurityManager用來表示以INI格式定義的使用者帳戶。

  [users]段落是指定使用者帳戶靜態列表的地方 - 為簡單應用或測試提供了方便。

  就介紹而言,詳細瞭解每個段落的細節並不是重點。相反,看到INI配置是一種配置Shiro的簡單方式才是關鍵。關於INI配置的更多細節,請參見Shiro文件。

  清單3. 裝入shiro.ini配置檔案

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.util.Factory;
...
//1.裝入INI配置 
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2. 建立SecurityManager 
SecurityManager securityManager = factory.getInstance();
//3. 使其可訪問 
SecurityUtils.setSecurityManager(securityManager);

  在清單3的示例中,我們看到有三步:

  裝入用來配置SecurityManager及其構成元件的INI配置檔案;

  根據配置建立SecurityManager例項(使用Shiro的工廠概念,它表述了工廠方法設計模式);

  使應用可訪問SecurityManager Singleton。在這個簡單示例中,我們將它設定為VM靜態Singleton,但這通常不是必須的 - 你的應用配置機制可以決定你是否需要使用靜態儲存。

  Realms

  Shiro的第三個也是最後一個概念是Realm。Realm充當了Shiro與應用安全資料間的“橋樑”或者“聯結器”。也就是說,當切實與像使用者帳戶這類安全相關資料進行互動,執行認證(登入)和授權(訪問控制)時,Shiro會從應用配置的Realm中查詢很多內容。

  從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了資料來源的連線細節,並在需要時將相關資料提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用於認證和(或)授權。配置多個Realm是可以的,但是至少需要一個。

  Shiro內建了可以連線大量安全資料來源(又名目錄)的Realm,如LDAP、關聯式資料庫(JDBC)、類似INI的文字配置資源以及屬性檔案等。如果預設的Realm不能滿足需求,你還可以插入代表自定義資料來源的自己的Realm實現。下面的清單4是通過INI配置Shiro使用LDAP目錄作為應用Realm的示例。

    

清單4. Realm配置示例片段:連線儲存使用者資料的LDAP

[main]
ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
ldapRealm.userDnTemplate = uid={0},ou=users,dc=mycompany,dc=com
ldapRealm.contextFactory.url = ldap://ldapHost:389
ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5

  既然已經瞭解如何建立一個基本的Shiro環境,下面讓我們來討論,作為一名開發者該如何使用這個框架。

相關文章