1. 程式人生 > >Shiro那些事兒(一): Shiro初探

Shiro那些事兒(一): Shiro初探

 引言

  許可權,可以簡單的理解成你能幹什麼,不能幹什麼。在管理系統中,對許可權的設計可以很簡單,也可以很複雜。簡單點的,基本都是基於角色扮演的方式,比如系統管理員角色可以操作哪些選單,普通使用者角色可以操作哪些選單等等,通過讓不同使用者扮演不同的角色,不同角色授予不同的選單許可權,來實現對訪問使用者的許可權控制。當然,這種簡單的設計其實是比較粗粒度的,僅僅是一種選單許可權的控制。如果系統比較大,對許可權的控制粒度會有更加明細的需求,不僅選單許可權有可訪問、可操作之分,角色之間還可能會有層級和群組的劃分,如果再深入一點,還可能涉及到資料許可權的控制等等。總之,系統許可權,說簡單其實也簡單,但要想設計好也不容易,具體要根據自己的系統大小和業務來考量。不過,就我們一般的系統而言,簡單的許可權控制就足夠滿足需求了。這方面,除了你自己進行許可權設計外,第三方也有很多優秀的許可權框架可供選擇,有名的比如 Spring 帝國中的 Security 模組, Apache 基金會的 Shiro 許可權框架等等;不過相較於Spring Security,Apache Shiro 在易用性和適用廣度方面,都是要稍微佔優的。所以,本系列,博主從頭開始,來講講 Shiro 的使用。

  在Shiro官網,對 Shiro 的簡介是:好用的 Java 安全框架,可執行身份驗證、授權、密碼和會話管理,它有三個核心元件:Subject, SecurityManager 和 Realm。

  這就是 Shiro 了。博主照搬得很簡略,因為我知道在你真的進入Shiro的世界之前,給你解釋再多你一樣很懵逼,還不如不說!其實,結合實際專案中使用經驗和蒐羅一些網路教程,最多給你一天時間,你就可以在面試的時候說你會使用 Shiro 了,而且還很有經驗;如果面試官要深究,怎麼吹就看你本事了。博主最開始也是視訊資料看了一天,加上幾個專案中的使用,應對日常開發是沒有壓力了,但是總還是感覺沒真正的認識 Shiro。一般什麼時候你會發現你原來會用的東西其實你不一定懂呢,就是你假裝自己很懂了裝逼給人看的時候。這也就是為什麼布衣博主要寫技術博的原因吧——通常情況下是,下筆的時候你對一個技能點還是一知半解,等你寫完了,可能就瞭然於胸了。因為寫技術博文需要構思,需要查閱很多資料以儘量減少錯漏,需要認知的廣度和深度,同時又要求能淺出;這種對知識的吸收、消化再輸出的過程,遠比看視訊寫 Hello Word 要痛苦得多,當然,成長也更顯著。這種以教為學的方式,其實就是我們熟悉的費曼學習法。

  話歸正題。關於Shiro,怎麼來開篇呢?以程式設計師學技能的尿性,基本上都始於 Hello Word,而大多也就止於Hello Word,難得深入其理,吸其精,啖其髓。而博主又不太喜歡直入,將 Shiro 的模組元件一啪啦的羅列,然後再概念化的解釋一通完事,這完全不是布衣博主的風格嘛!而且,基於費曼學習大法,博主知道,那些已有的概念,並不能讓另一個小白似的自己真正的搞懂Shiro,反而會因為概念性的東西灌輸太多而更加懵逼。所以,在看博文的你大可以省省心,博主不會過多的作概念定義,只是按照個人對 Shiro 的有限認知看圖說話;說不定一席嘮叨下來,作為讀者的你,稍微利用點帶薪蹲坑的時間,就搞懂 Shiro 了呢。

  關於 Shiro 系列,博主的整體思路是,先從整個框架的架構講起,知其大略,然後分講各個模組,最後將各部分綜合成一個完整的 Hello Word 式的 Demo 專案;全系講完,你還不懂,算我服你!

 鳥瞰 

  既要知其大略,肯定是要搞懂Shiro的功能架構的。關於Shiro的架構,官網和各種教程中都有架構圖,但博主覺得直接上圖,有點突兀;至少,以自己小白的觀點來看,你直接給我看 Shiro 的架構圖,我的腦袋是凌亂的。所以博主換了個清新的思路,既然官網都是言簡意賅的擺明了 Shiro 的功能主要由三個核心的元件來完成,那麼我們就先來認識一下 Subject,SecurityManager和Realm 這三個核心元件到底在 Shiro 的功能實現中,都起著什麼樣的作用。

  Subject,主題,是 Shiro 功能核心中相當重要的一環,那它到底是個什麼玩意兒呢?你可以從兩點來認識它:

    第一,從框架功能上來說,Subject 在 Shiro 中指當前”使用者”。注意這個使用者是打引號的,意味著它並不是我們通常以人為語境來理解的那個使用者。按照官方文件的說法,這個使用者是 "a security-specific view of the currently executing user",是當前正在執行使用者的特殊安全檢視,可以是第三方服務,如守護程序,爬蟲等。當然,官方解釋就是很官方,小白一點的看了跟沒看一樣;博主覺得官方文件對Subject "非人" 概念的強調有點過了,其實在你使用的大多數場景中,你完全就可以理解成我們一般語境下的使用者,因為我們系統的許可權,基本都是基於人的使用者許可權。

    第二,從框架架構上來說,Subject 是框架執行認證、授權功能的門戶,這也就意味著你的認證、授權都要通過它來進行的,這是Shiro中典型的門面(外觀)模式的應用。

    門面模式,是指提供一個統一的介面去訪問多個子系統的多個不同的介面,它為子系統中的一組介面提供一個統一的高層介面,使得子系統更容易使用。

    下面是布衣博主對門面模式的圖形化翻譯:

 

  如上圖示,所有的禿頂程式設計師看病都是通過掛號視窗進行掛號後再被導診到各自的病患區域,而不是自己滿醫院的亂找大夫。看得出來,充當門面的掛號視窗對外提供了統一的入院方式,統籌科室資源,遮蔽科室間的差異性——你只要有病,不管什麼病,去掛號就對了。有了這層認知,Subject 理解起來就沒什麼難度了,因為在Shiro 中,Subject 的作用一樣的,不管你是要登入認證,使用者授權還是會話管理,都需要通過 Subject 這樣一個門面物件。恰如看病掛號的簡潔一樣,你也不用擔心 Subject 物件的建立會有多複雜。實際上,在應用程式的任何地方,你只需要大吼三聲,"爺爺在此",啊不,是來一句 SecurityUtils.getSubject() ,Shiro 就把 Subject 物件構建好給你了,對使用者來說,API 真的是非常簡單易用的;而構建 Subject 門面物件的複雜性被 Shiro 採用建造者模式封裝在框架內部,對呼叫者是無感的。Shiro 通過這種門面模式的設計,提供給呼叫者統一的門面介面,從而遮蔽掉了訪問Shiro框架內部API的複雜性;同時,統一的對外介面,可以遮蔽跟當前跟軟體互動的外部的不同語言系統、不同服務呼叫的差異性,極大的拓展了Shiro的使用場景。

   SecurityManager,安全管理器,所有與安全有關的操作都需要通過它,它是整個 Shiro 框架的功能核心。

  上文我們說到門面物件 Subject,它只是個門面物件,就像看病的掛號視窗一樣,並不完成具體的看病功能,你要看病,還得去各科室找大夫。而  SecurityManager 物件,就是在幕後幫你完成具體功能的。當然,博主這樣說還是有一定的誤導性,讓你覺得 Shiro 的認證、授權、會話管理等這些功能的完成都是 SecurityManager 自己在幹——有這樣的想法,只能說你還太嫩了!哪怕你自己去設計框架,你會把所有的功能都揉成一團放到一個物件中去實現?實際上,基於責任分離的原則,SecurityManager  本身也並不完成具體的功能,它只負責需求排程,具體的功能完成都分配到具體的功能元件,比如登入認證就找登入認證元件(Authentication),授權找授權元件(Authorization),會話找會話元件(Session Manager),資料比對就找資料來源元件(Realm)等等。是的,也許你已經明白過來了,這不就是Spring MVC中的核心排程器 DispatcherServlet 嘛。you are smart !在Spring MVC 中,你除了確保 DipacherServlet 的啟動建立以外,在使用過程中你並不會直接和 DispacherServlet 物件打交道,它的核心工作都在幕後(框架內部)完成;Shiro 中的 SecurityManager 也是一樣,我們要做的,就是保證應用程式啟動的時候,能夠創建出全域性唯一的安全管理器例項,讓該例項在幕後幫我們完成安全有關的認證、授權和會話管理等工作。

  所以,在你的專案開發中,對 SecurityManager 物件的主要工作在於,根據不同的應用程式,完成適合 SecurityManager 物件建立的配置。基於前面的闡述你也知道了,安全管理器的建立是依賴於認證、授權,快取、資料來源等諸多元件的,你可以各自建立功能元件物件然後交給 SecurityManger ,但為了專案的靈活性,通常並不建議直接在程式碼中用 new 的方式來建立物件,而應該是在配置檔案中來完成安全管理器構建所需的元件配置。配置的方式,選擇很多,比如你可以通過 Spring XML 配置,也可以用 YAML 檔案或者 Properties檔案配置等,但就易用性和可讀性來講, ini 檔案配置方式才是更通用的選擇。

   Realm:領域物件,在 Shiro 和你的應用程式安全資料(比如登入的使用者名稱、密碼,使用者的許可權等)之間架起一座溝通的橋樑,不然 Shiro 怎麼知道你介面提交的登入使用者合不合法,有沒有某種許可權呢? 結合上面介紹的安全管理器的功能表述,博主可以這樣來給你進一步解釋:安全管理器要驗證使用者身份,或者要獲取使用者對應的許可權,是分別通過認證元件(Authentication)和授權元件(Authorization)來具體完成的,但是這兩個元件要完成認證或授權的實際功能,又需要與安全有關的資料做支撐,這個時候,他們就要從 Realm 那裡獲取相應的使用者資料進行比較以確定登入使用者身份是否合法,或者從 Realm 那裡得到使用者相應的角色 / 許可權以驗證使用者是否能進行某些操作操作。所以,通常在程式設計師的語境中,我們可以把 Realm 看成是我們熟悉的DataSource,即安全資料來源。既然 Shiro 是關於安全的框架,那麼 Realm 就必不可少,所以在實際使用中,你必須至少配置一個 Realm 才能保證框架的正常執行。這裡著重強調至少,也就意味著你可以配置多個 Realm,這也是 Shiro 很有意思的地方,讓你可以自由的控制程式的安全認證級別。關於多Realm認證,後面的系列文章會詳解。最後說明,在Shiro中,Realm 作為一種安全資料抽象,針對不同的安全資料來源,提供了很多開箱即用的具體實現,讓你可以很方便的從諸如資料庫系統,LDAP(輕量目錄訪問協議),配置檔案等渠道獲取安全資料。當然,在實際開發中,我們用得更多的還是自己定義 Realm 實現的方式來使用 Realm。                  

  自此,你搞懂Shiro中 Subject,SecurityManager和 Realm 這三個核心元件之間的三角關係了嗎?由於布衣博主是個直男,特意將官網上已有的核心元件之間的關係圖強行掰直了給你看以加深你的理解:

                                  

 圖解

   

    

 

  經過上面對Shiro的核心三元件的分析,現在博主再給你奉上 Shiro 官網提供的框架架構圖,你是不是有了自己更加清晰的認知了呢?

  還是簡單的來看圖說話。從架構圖中我們可以看到,門面物件 Subject 和博主舉例中的掛號視窗功能是一樣一樣的,通過 Subject 物件,不光 Java 中的 Web 應用或普通的單體應用自己能夠訪問安全模組實現業務功能,其它語言如 C/C++,Ruby,Python 等也能通過外部介面呼叫的方式訪問 Shiro 的核心安全模組。而 Shiro內部核心 SecurityManager 的功能實現是由它內部管理的具體的功能元件如認證(Authentication),授權(Authorization),會話管理器(Session Manager),快取管理器(Cache Manager),會話 DAO(Session DAO【將session儲存到資料庫、快取等】),各種 Realm 實現等來協作完成的。此外,由於是安全框架,Shiro 提供了額外的密碼模組 Cryptography,這是一個獨立的模組,所以你可以將該模組當成密碼工具箱一樣單獨應用到你專案的業務邏輯中,為各種加解密相關的操作提供便利。

  上圖看懂了,關於 Shiro 你至少已經懂了一大半了。剩下的工作其實已經很簡單而清晰了,就是基於對功能架構的清晰認知,我們分模組的,從具體的程式碼層面來編寫具體的業務實現,如登入、授權、管理會話等。

  OK,Talk is cheap,Show me the code!擼碼去,下期