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,SecurityManagerRealm 這三個核心組件到底在 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,SecurityManagerRealm 這三個核心組件之間的三角關系了嗎?由於布衣博主是個直男,特意將官網上已有的核心組件之間的關系圖強行掰直了給你看以加深你的理解:

                                 

 圖解

   

    

 

  經過上面對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 你至少已經懂了一大半了。剩下的工作其實已經很簡單而清晰了,就是基於對 Shiro 功能架構的清晰認知,我們分模塊的,從具體的代碼層面來編寫具體的業務實現,來解決“應用程序安全的四大基石”——身份驗證,授權,會話管理和加密的具體問題。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM