1. 程式人生 > >SpringBoot整合Shiro三個漸進式專案以及Shiro功能介紹

SpringBoot整合Shiro三個漸進式專案以及Shiro功能介紹

首先,本篇部落格的目的的重點是這裡介紹的三個SpringBoot整合Shiro的專案,從簡入繁,從最簡單的例項講解起,到最後的繼承Redis,動態更新許可權等等
在本篇部落格的後面,也介紹了一些Shiro的基礎知識點。例如Shiro的四大基石等等

spring-boot-shiro 專案說明

spring-boot-shiro-hello-world

springboot整合shiro的入門專案
使用註解配置攔截以及使用ShiroFilterFactoryBean進行配置攔截器
使用靜態配置許可權,異常跳轉等

spring-boot-shiro-mysql

springboot整合shiro,使用mysql資料庫,動態從資料庫讀取許可權配置
並且更新資料庫的許可權表,不用重啟專案即可進行更新shiro許可權過濾器
前端頁面使用freemarker引擎模板渲染,根據許可權動態顯示選單
全域性異常的攔截處理
使用Shiro進行鹽的獲取以及密碼進行MD5加密儲存
generator自定義註釋輸出表註釋和欄位註釋

spring-boot-shiro-redis

本專案主要是整合redis快取
druid 監控配置配置
配置了記住我的功能,其實就是儲存到客戶端的Cookie

GitHub開源地址

Shiro介紹

Shiro是什麼
Apache Shiro是一個開源的安全框架。可以處理身份驗證,授權,會話管理,加密,快取等

Shrio的基本功能圖:
Shrio的基本功能圖

最主要功能(也稱為Shiro的四大基石):
1. Authentication:身份認證/登入,驗證使用者是不是擁有相應的身份;
2. Authorization:授權,即許可權驗證,驗證某個已認證的使用者是否擁有某個許可權;即判斷使用者是否能做事情,常見的如:驗證某個使用者是否擁有某個角色。或者細粒度的驗證某個使用者對某個資源是否具有某個許可權;
3. Session Manager:會話管理,即使用者登入後就是一次會話,在沒有退出之前,它的所有資訊都在會話中;會話可以是普通JavaSE環境的,也可以是Web環境的;
4. Cryptography:加密,保護資料的安全性,如密碼加密儲存到資料庫,而不是明文儲存;

輔助特性:
1. Web Support:Web支援,可以非常容易的整合到Web環境;
2. Caching:快取,比如使用者登入後,其使用者資訊、擁有的角色/許可權不必每次去查,這樣可以提高效率;
3. Concurrency:shiro支援多執行緒應用的併發驗證,即如在一個執行緒中開啟另一個執行緒,能把許可權自動傳播過去;
4. Testing:提供測試支援;
5. Run As:允許一個使用者假裝為另一個使用者(如果他們允許)的身份進行訪問;
6. Remember Me:記住我,這個是非常常見的功能,即一次登入後,下次再來的話不用登入了。

一般情況下,我們在開發中常用的也就是Shiro的身份驗證,授權和加密,另外Remember Me可能也會經常用到,快取一般是整合Redis進行。
主要也就是講解該部分。對於一個好的框架,從外部來看應該具有非常簡單易於使用的API,且API契約明確;從內部來看的話,其應該有一個可擴充套件的架構,即非常容易插入使用者自定義實現,因為任何框架都不能滿足所有需求。

首先,我們從外部來看Shiro,也就是從應用程式的角度檢視Shiro是如何完成工作的
外部來看Shiro

從該圖中,可以看出,我們應用程式碼直接進行互動的物件是Subject,也就是說Shiro中的對外API核心就是Subject。
1. Subject:主體,代表了當前“使用者”,這個使用者不一定是一個具體的人,與當前應用互動的任何東西都是Subject,如網路爬蟲,機器人等;即一個抽象概念;所有Subject都繫結到SecurityManager(安全管理器),與Subject的所有互動都會委託給SecurityManager;可以把Subject認為是一支筆;SecurityManager才是實際的持筆人;
2. SecurityManager:安全管理器;即所有與安全有關的操作都會與SecurityManager互動;且它管理著所有Subject;可以看出它是Shiro的核心,它負責與Shiro的其他元件進行互動,你可以把它看成SpringMVC中的DispatcherServlet前端控制器;
3. Realm:領域,Shiro從從Realm獲取安全資料(如使用者、角色、許可權),就是說SecurityManager要驗證使用者身份,那麼它需要從Realm獲取相應的使用者進行比較以確定使用者身份是否合法;也需要從Realm得到使用者相應的角色/許可權進行驗證使用者是否能進行操作;可以把Realm看成DataSource,也就是安全資料來源。領域可以配置一個或者多個。

Realm本質上是一個特定情況的DAO,它封裝了資料來源的連線細節,並且根據需要,Shiro可以獲取相關的資料,配置Shiro時,至少需要指定一個Realm,用於身份認證或者授權。所以SecurityManager可能配置多個Realm,但是至少需要配置一個。

Shrio中也提供了一些開箱即用的Realm,可以連線到許多的安全資料來源,比如LDAP(輕量目錄訪問協議),關係資料庫(JDBC),文字配置源(INI檔案或者屬性檔案等)。如果這些無法滿足需求,可以插入自己的Realm實現自定義的資料庫,一般情況下,使用文字和資料庫即夠用了。

SecurityManager負責管理如何獲取和使用Realm作為Subject例項的安全性和身份資料。也就是說對於我們而言,最簡單的一個Shiro應用,實現身份驗證和授權需要下面的幾步:
1. 應用程式碼通過Subject來進行認證和授權,而Subject又委託給SecurityManager;
2. 我們需要給Shiro的SecurityManager注入Realm,從而讓SecurityManager能得到合法的使用者及其許可權進行判斷。

Shiro不提供使用者和許可權,需要開發人員通過Realm自己進行注入。可以靜態注入,也可以動態更新,後面在程式碼中會演示到

接下來看下Shrio內部的核心架構圖
Shrio內部的核心架構圖

  1. Subject (org.apache.shiro.subject.Subject):主體。理解為和應用程式互動的安全性的”檢視”
  2. SecurityManager (org.apache.shiro.mgt.SecurityManager):安全管理器。Shiro的核心,類比於Spring MVC中的前端控制器DispatcherServlet.Shiro和應用程式的所有具體互動都會通過SecurityManager進行控制。管理所有的Subject,負責進行認證,授權,會話以及快取的管理
  3. Authenticator (org.apache.shiro.authc.Authenticator):認證器。負責執行和響應使用者進行身份驗證(登入)的元件。可以自定義實現,實現認證策略即可,也就是什麼情況下算使用者成功認證了。
  4. Authentication Strategy (org.apache.shiro.authc.pam.AuthenticationStrategy):認證策略。如果配置了多個領域,AuthenticationStrategy會協調領域確認身份認證成功或者失敗的條件。比如說,一個領域認證成功,其他領域全部認證失敗,那麼是認證成功還是失敗?
  5. Authorizer (org.apache.shiro.authz.Authorizer):授權器。授權器是決定應用程式中使用者訪問控制的元件,是一種機制,用來決定使用者是否有許可權進行相應的操作。即控制使用者能夠訪問應用程式中哪些功能。
  6. SessionManager (org.apache.shiro.session.mgt.SessionManager):會話管理。Session的概念和我們在Servlet中的概念一致。會話管理是用來管理Session的生命週期的。由於Shiro不僅僅只用在Web環境下,也可以在普通的JavaSE環境下使用。所以Shiro就抽象出自己的一個Session管理器來管理主體和應用之間互動的資料。如需要實現分散式,則使用Redis管理Session即可。
  7. SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO):SessionDAO的存在是為了允許任何資料來源用於持久化會話。DAO大家都用過,資料訪問物件,用於會話的CRUD(持久化),比如我們想把Session儲存到資料庫,那麼可以實現自己的SessionDAO,通過JDBC寫到資料庫;比如想把Session放到Redis中,可以實現自己的Redis SessionDAO;另外SessionDAO中可以使用Cache進行快取,以提高效能;
  8. CacheManager (org.apache.shiro.cache.CacheManager):快取控制器。快取控制器,來管理如使用者、角色、許可權等的快取的;因為這些資料基本上很少去改變,放到快取中後可以提高訪問的效能。如果需要動態更新許可權,如果實現了快取,那麼同時需要更新該元件。
  9. Cryptography (org.apache.shiro.crypto.*):密碼模組。Shiro提供了一些常見的加密元件用於密碼加密/解密。雜湊演算法MD5,SHA等,base64等
  10. Realms (org.apache.shiro.realm.Realm):可以有1個或多個Realm,可以認為是安全實體資料來源,即用於獲取安全實體的;可以是JDBC實現,也可以是LDAP(輕量目錄訪問協議)實現,或者記憶體實現等等;由使用者提供;注意:Shiro不知道你的使用者/許可權儲存在哪及以何種格式儲存;所以我們一般在應用中都需要實現自己的Realm;

使用Shiro

未整合Spring/SpringBoot以前,是需要在Web.xml中定義org.apache.shiro.web.servlet.ShiroFilter過濾器的
Shiro的初始化工作在web.xml中設定監聽器完成

<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Shiro 的 EnvironmentLoaderListener 就是一個典型的 ServletContextListener,它也是整個 Shiro Web 應用的入口 。

EventListener 是一個標誌介面,裡面沒有任何的方法,Servlet 容器中所有的 Listener 都要繼承這個介面(這是 Servlet 規範)。

EnvironmentLoaderListener

ServletContextListener 是一個 ServletContext 的監聽器,用於監聽容器的啟動與關閉事件,包括如下兩個方法:
void contextInitialized(ServletContextEvent sce); // 當容器啟動時呼叫
void contextDestroyed(ServletContextEvent sce); // 當容器關閉時呼叫

可以從 ServletContextEvent 中直接獲取 ServletContext 物件。

EnvironmentLoaderListener 不僅實現了 ServletContextListener 介面,也擴充套件了 EnvironmentLoader 類,應該是需要在 Servlet 容器中呼叫 EnvironmentLoader 物件的生命週期方法
從 Shiro 1.2 開始引入了 Environment/WebEnvironment 的概念,即由它們的實現提供相應的 SecurityManager 及其相應的依賴。ShiroFilter 會自動找到 Environment 然後獲取相應的依賴。
通過 EnvironmentLoaderListener 來建立相應的 WebEnvironment,並自動繫結到 ServletContext,預設使用 IniWebEnvironment 實現。

EnvironmentLoader的功能:
1. 當容器啟動時,讀取 web.xml 檔案,從中獲取 WebEnvironment 介面的實現類(預設是 IniWebEnvironment),初始化該例項,並將其載入到 ServletContext 中。
2. 當容器關閉時,銷燬 WebEnvironment 例項,並從 ServletContext 將其移除。

IniWebEnvironment的功能:
1. 查詢並載入 shiro.ini 配置檔案,首先從自身成員變數裡查詢,然後從 web.xml 中查詢,然後從 /WEB-INF 下查詢,然後從 classpath 下查詢,若均未找到,則直接報錯。
2. 當找到了 ini 配置檔案後就開始解析,此時構造了一個 Bean 容器(相當於一個輕量級的 IOC 容器),最終的目標是為了建立 WebSecurityManager 物件與 FilterChainResolver 物件,建立過程使用了 Abstract Factory 模式

EnvironmentLoaderListener無非就是在容器啟動時建立 WebEnvironment 物件,並由該物件來讀取 Shiro 配置檔案,建立WebSecurityManager(安全管理器)與 FilterChainResolver(過濾鏈解析器) 物件,在ShiroFilter中起到了重要作用。

ShiroFilter 是整個 Shiro 的入口點,用於攔截需要安全控制的請求進行處理。
因為它攔截了所有的請求,後面的 Authentication(認證)和Authorization(授權)都由ShiroFilter說了算

和Spring/SpringBoot整合以後,我們只需要注入ShiroFilter即可,ShiroFilter由ShiroFilterFactoryBean負責建立。所以注入ShiroFilterFactoryBean,由 ShiroFilterFactoryBean建立 ShiroFilter即可

Shiro介紹參考博文

參與貢獻

陳浩翔
部落格寫的比較匆忙,程式碼/部落格中若有錯誤的地方,歡迎指正。