讓Apache Shiro保護你的應用

jopen 10年前發布 | 37K 次閱讀 Shiro 安全相關 Apache Shiro

在嘗試保護你的應用時,你是否有過挫敗感?是否覺得現有的Java安全解決方案難以使用,只會讓你更糊涂?本文介紹的Apache Shiro,是一個不同尋常的Java安全框架,為保護應用提供了簡單而強大的方法。本文還解釋了Apache Shiro的項目目標、架構理念以及如何使用Shiro為應用安全保駕護航。

什么是Apache Shiro?

Apache Shiro(發音為“shee-roh”,日語“堡壘(Castle)”的意思)是一個強大易用的Java安全框架,提供了認證、授權、加密和會話管理功能,可為任何應用提供安全保障 - 從命令行應用、移動應用到大型網絡及企業應用

Shiro為解決下列問題(我喜歡稱它們為應用安全的四要素)提供了保護應用的API:

  • 認證 - 用戶身份識別,常被稱為用戶“登錄”;

  • 授權 - 訪問控制;

  • 密碼加密 - 保護或隱藏數據防止被偷窺;

  • 會話管理 - 每用戶相關的時間敏感的狀態。

Shiro還支持一些輔助特性,如Web應用安全、單元測試和多線程,它們的存在強化了上面提到的四個要素。

為何要創建Apache Shiro?

    對于一個框架來講,使其有存在價值的最好例證就是有讓你去用它的原因,它應該能完成一些別人無法做到的事情。要理解這一點,需要了解Shiro的歷史以及創建它時的其他替代方法。

    在2008年加入Apache軟件基金會之前,Shiro已經5歲了,之前它被稱為JSecurity項目,始于2003年初。當時,對于Java應用開發人員而言,沒有太多的通用安全替代方案 - 我們被Java認證/授權服務(或稱為JAAS)緊緊套牢了。JAAS有太多的缺點 - 盡管它的認證功能尚可忍受,但授權方面卻顯得拙劣,用起來令人沮喪。此外,JAAS跟虛擬機層面的安全問題關系非常緊密,如判斷JVM中是否允許裝入一個類。作為應用開發者,我更關心應用最終用戶能做什么,而不是我的代碼在JVM中能做什么

    由于當時正從事應用開發,我也需要一個干凈、容器無關的會話機制。在當時,“這場游戲”中唯一可用的會話是HttpSessions,它需要Web容器;或是EJB 2.1里的有狀態會話Bean,這又要EJB容器。而我想要的一個與容器脫鉤、可用于任何我選擇的環境中的會話。

    最后就是加密問題。有時,我們需要保證數據安全,但是Java密碼架構(Java Cryptography Architecture)讓人難以理解,除非你是密碼學專家。API里到處都是Checked Exception,用起來很麻煩。我需要一個干凈、開箱即用的解決方案,可以在需要時方便地對數據加密/解密。

    于是,縱觀2003年初的安全狀況,你會很快意識到還沒有一個大一統的框架滿足所有上述需求。有鑒于此,JSecurity(即之后的Apache Shiro)誕生了

今天,你為何愿意使用Apache Shiro?

從2003年至今,框架選擇方面的情況已經改變了不少,但今天仍有令人信服的理由讓你選擇Shiro。其實理由相當多,Apache Shiro:

  • 易于使用 - 易用性是這個項目的最終目標。應用安全有可能會非常讓人糊涂,令人沮喪,并被認為是“必要之惡”【譯注:比喻應用安全方面的編程。】。若是能讓它簡化到新手都能很快上手,那它將不再是一種痛苦了。

  • 廣泛性 - 沒有其他安全框架可以達到Apache Shiro宣稱的廣度,它可以為你的安全需求提供“一站式”服務。

  • 靈活性 - Apache Shiro可以工作在任何應用環境中。雖然它工作在Web、EJB和IoC環境中,但它并不依賴這些環境。Shiro既不強加任何規范,也無需過多依賴。

  • Web能力 - Apache Shiro對Web應用的支持很神奇,允許你基于應用URL和Web協議(如REST)創建靈活的安全策略,同時還提供了一套控制頁面輸出的JSP標簽庫。

  • 可插拔 - Shiro干凈的API和設計模式使它可以方便地與許多的其他框架和應用進行集成。你將看到Shiro可以與諸如Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin這類第三方框架無縫集成。

  • 支持 - Apache Shiro是Apache軟件基金會成員,這是一個公認為了社區利益最大化而行動的組織。項目開發和用戶組都有隨時愿意提供幫助的友善成員。像Katasoft這類商業公司,還可以給你提供需要的專業支持和服務。

誰在用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</pre>

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

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

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

  2. 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的示例中,我們看到有三步:

  1. 裝入用來配置SecurityManager及其構成組件的INI配置文件;

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

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

  4. </ol>

    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環境,下面讓我們來討論,作為一名開發者該如何使用這個框架。


    原文地址:http://www.infoq.com/cn/articles/apache-shiro

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!