shiro詳解-shiro史上最全學習筆記
1.shiro簡介
1.1.基本功能點
Shiro 可以非常容易的開發出足夠好的應用,其不僅可以用在 JavaSE 環境,也可以用在 JavaEE 環境。Shiro 可以幫助我們完成:認證、授權、加密、會話管理、與 Web 整合、快取等。其基本功能點如下圖所示:
- Authentication:身份認證 / 登入,驗證使用者是不是擁有相應的身份;
- Authorization:授權,即許可權驗證,驗證某個已認證的使用者是否擁有某個許可權;即判斷使用者是否能做事情,常見的如:驗證某個使用者是否擁有某個角色。或者細粒度的驗證某個使用者對某個資源是否具有某個許可權;
- Session Manager:會話管理,即使用者登入後就是一次會話,在沒有退出之前,它的所有資訊都在會話中;會話可以是普通 JavaSE 環境的,也可以是如 Web 環境的;
- Cryptography:加密,保護資料的安全性,如密碼加密儲存到資料庫,而不是明文儲存;
- Web Support:Web 支援,可以非常容易的整合到 Web 環境;
- Caching:快取,比如使用者登入後,其使用者資訊、擁有的角色 / 許可權不必每次去查,這樣可以提高效率;
- Concurrency:shiro 支援多執行緒應用的併發驗證,即如在一個執行緒中開啟另一個執行緒,能把許可權自動傳播過去;
- Testing:提供測試支援;
- Run As:允許一個使用者假裝為另一個使用者(如果他們允許)的身份進行訪問;
- Remember Me:記住我,這個是非常常見的功能,即一次登入後,下次再來的話不用登入了。
記住一點,Shiro 不會去維護使用者、維護許可權;這些需要我們自己去設計 / 提供;然後通過相應的介面注入給 Shiro 即可。
1.2.Shiro的架構
1.2.1.外部
我們從外部來看 Shiro ,即從應用程式角度的來觀察如何使用 Shiro 完成工作。如下圖:
可以看到:應用程式碼直接互動的物件是 Subject,也就是說 Shiro 的對外 API 核心就是 Subject;其每個 API 的含義:
Subject:主體,代表了當前 “使用者”,這個使用者不一定是一個具體的人,與當前應用互動的任何東西都Subject,如網路爬蟲,機器人等;即一個抽象概念;所有 Subject 都繫結到 SecurityManager,與 Subject 的所有互動都會委託給 SecurityManager;可以把 Subject 認為是一個門面;SecurityManager 才是實際的執行者;
SecurityManager:安全管理器;即所有與安全有關的操作都會與 SecurityManager 互動;且它管理著所有 Subject;可以看出它是 Shiro 的核心,它負責與後邊介紹的其他元件進行互動,如果學習過 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;
Realm:域,Shiro 從 Realm 獲取安全資料(如使用者、角色、許可權),就是說 SecurityManager 要驗證使用者身份,那麼它需要從 Realm 獲取相應的使用者進行比較以確定使用者身份是否合法;也需要從 Realm 得到使用者相應的角色 / 許可權進行驗證使用者是否能進行操作;可以把 Realm 看成 DataSource,即安全資料來源。
也就是說對於我們而言,最簡單的一個 Shiro 應用:
- 應用程式碼通過 Subject 來進行認證和授權,而 Subject 又委託給 SecurityManager;
- 我們需要給 Shiro 的 SecurityManager 注入 Realm,從而讓 SecurityManager 能得到合法的使用者及其許可權進行判斷。
從以上也可以看出,Shiro 不提供維護使用者 / 許可權,而是通過 Realm 讓開發人員自己注入。
1.2.2.內部
接下來我們來從 Shiro 內部來看下 Shiro 的架構,如下圖所示:
Subject:主體,可以看到主體可以是任何可以與應用互動的 “使用者”;
SecurityManager:相當於 SpringMVC 中的 DispatcherServlet 或者 Struts2 中的 FilterDispatcher;是 Shiro 的心臟;所有具體的互動都通過 SecurityManager 進行控制;它管理著所有 Subject、且負責進行認證和授權、及會話、快取的管理。
Authenticator:認證器,負責主體認證的,這是一個擴充套件點,如果使用者覺得 Shiro 預設的不好,可以自定義實現;其需要認證策略(Authentication Strategy),即什麼情況下算使用者認證通過了;
Authrizer:授權器,或者訪問控制器,用來決定主體是否有許可權進行相應的操作;即控制著使用者能訪問應用中的哪些功能;
Realm:可以有 1 個或多個 Realm,可以認為是安全實體資料來源,即用於獲取安全實體的;可以是 JDBC 實現,也可以是 LDAP 實現,或者記憶體實現等等;由使用者提供;注意:Shiro 不知道你的使用者 / 許可權儲存在哪及以何種格式儲存;所以我們一般在應用中都需要實現自己的 Realm;
SessionManager:如果寫過 Servlet 就應該知道 Session 的概念,Session 呢需要有人去管理它的生命週期,這個元件就是 SessionManager;而 Shiro 並不僅僅可以用在 Web 環境,也可以用在如普通的 JavaSE 環境、EJB 等環境;所有呢,Shiro 就抽象了一個自己的 Session 來管理主體與應用之間互動的資料;這樣的話,比如我們在 Web 環境用,剛開始是一臺 Web 伺服器;接著又上了臺 EJB 伺服器;這時想把兩臺伺服器的會話資料放到一個地方,這個時候就可以實現自己的分散式會話(如把資料放到 Memcached 伺服器);
SessionDAO:DAO 大家都用過,資料訪問物件,用於會話的 CRUD,比如我們想把 Session 儲存到資料庫,那麼可以實現自己的 SessionDAO,通過如 JDBC 寫到資料庫;比如想把 Session 放到 Memcached 中,可以實現自己的 Memcached SessionDAO;另外 SessionDAO 中可以使用 Cache 進行快取,以提高效能;
CacheManager:快取控制器,來管理如使用者、角色、許可權等的快取的;因為這些資料基本上很少去改變,放到快取中後可以提高訪問的效能
Cryptography:密碼模組,Shiro 提高了一些常見的加密元件用於如密碼加密 / 解密的。
2.shiro元件
2.1.身份驗證
身份驗證,即在應用中誰能證明他就是他本人。一般提供如他們的身份 ID 一些標識資訊來表明他就是他本人,如提供身份證,使用者名稱 / 密碼來證明。
在 shiro 中,使用者需要提供 principals (身份)和 credentials(證明)給 shiro,從而應用能驗證使用者身份:
principals:身份,即主體的標識屬性,可以是任何東西,如使用者名稱、郵箱等,唯一即可。一個主體可以有多個 principals,但只有一個 Primary principals,一般是使用者名稱 / 密碼 / 手機號。
credentials:證明 / 憑證,即只有主體知道的安全值,如密碼 / 數字證書等。
最常見的 principals 和 credentials 組合就是使用者名稱 / 密碼了。接下來先進行一個基本的身份認證。
另外兩個相關的概念是之前提到的Subject及Realm,分別是主體及驗證主體的資料來源。
2.1.1.maven依賴配置
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<shiro.version>1.2.2</shiro.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.2</version>
</dependency>
<!-- shiro相關依賴 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId