Shiro 權限校驗分析

1. Shiro 概述

Shiro 是一款 Apache 提供的權限校驗框架, Shiro 同時也是一個強大且易用的 Java 安全框架,執行身份驗證、授權、密碼學和會話管理。使用 Shiro 的易於理解的 API,您可以快速、輕鬆地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序,特別是今天對權限校驗和管理特別嚴格,大家有必要對shiro 有一個基本的認識和學習。

2. Shiro 的三大核心組件

1、Subject :當前用戶的操作

2、SecurityManager:用於管理所有的 Subject 3、Realms:用於進行權限信息的驗證

如下圖:各組件之間的調用關係:

Shiro 權限校驗分析

· Subject:翻譯為主角,當前參與應用安全部分的主角。可以是用戶,可以是第三方服務,可以是 cron 任務,或者任何東西。主要指一個正在與當前軟件交互的東西。所有 Subject 都需要 SecurityManager,當你與 Subject 進行交互,這些交互行為實際上被轉換為與 SecurityManager 的交互

· SecurityManager:安全管理員,Shiro 架構的核心,它就像 Shiro 內部所有原件的保護傘。然而一旦配置了 SecurityManager,SecurityManager 就用到的比較少,開發者大部分時間都花在 Subject 上面請記得,當你與 Subject 進行

交互的時候,實際上是 SecurityManager 在背後幫你舉起 Subject 來做一些安全操作。

· Realms:Realms 作為 Shiro 和你的應用的連接橋,當需要與安全數據交互的時候,像用戶賬戶,或者訪問控制,Shiro 就從一個或多個 Realms 中查找。Shiro 提供了一些可以直接使用的 Realms,如果默認的 Realms 不能滿足你的需求,你也可以定製自己的 Realms.


3. Shiro 的十大功能特點:

3.1 功能特點

Shiro 包含 10 個內容,如下圖:

Shiro 權限校驗分析

1. Authentication:身份認證/登錄,驗證用戶是不是擁有相應的身份。

2. Authorization:授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限; 即判斷用戶是否能做事情,常見的如:驗證某個用戶是否擁有某個角色。或者細粒度的驗證某個用戶對某個資源是否具有某個權限。

3. Session Manager:會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通 JavaSE 環境的,也可以是如 Web 環境的。

4. Cryptography:加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲。

5. Web Support:Web 支持,可以非常容易的集成到 web 環境。

6. Caching:緩存,比如用戶登錄後,其用戶信息、擁有的角色/權限不必每次去查, 這樣可以提高效率。

7. Concurrency:shiro 支持多線程應用的併發驗證,即如在一個線程中開啟另一個線程,能把權限自動傳播過去。

8. Testing:提供測試支持。

9. Run As:允許一個用戶假裝為另一個用戶(如果他們允許)的身份進行訪問。

10. Remember Me:記住哦,這個是非常常見的功能,即一次登錄後,下次再來的話不用登錄了。

4. Shiro 的運行原理

Shiro 權限校驗分析

1) Subject:主體,可以看到主體可以是任何與應用交互的"用戶"。

2) SecurityManager:相當於 SpringMVC 中的 DispatcherServlet 或者 Struts2 中的 FilterDispatcher。它是 Shiro 的核心,所有具體的交互都通過

SecurityManager 進行控制。它管理著所有 Subject、且負責進行認證和授權、及會話、緩存的管理。

3) Authenticator:認證器,負責主體認證的,這是一個擴展點,如果用戶覺得Shiro 默認的不好,我們可以自定義實現。其需要認證策略(Authentication Strategy),即什麼情況下算用戶認證通過了。

4) Authrizer:授權器,或者訪問控制器。它用來決定主體是否有權限進行相應的操作,即控制著用戶能訪問應用中的哪些功能。

5) Realm:可以有 1 個或多個 Realm,可以認為是安全實體數據源,即用於獲取安全實體的。它可以是 JDBC 實現,也可以是 LDAP 實現,或者內存實現等。

6) SessionManager:如果寫過 Servlet 就應該知道 Session 的概念,Session 需要有人去管理它的生命週期,這個組件就是 SessionManager。而 Shiro 並不僅僅可以用在 Web 環境,也可以用在如普通的 JavaSE 環境。

7) SessionDAO:DAO 大家都用過,數據訪問對象,用於會話的 CRUD。我們可以自定義 SessionDAO 的實現,控制 session 存儲的位置。如通過 JDBC 寫到數據庫或通過jedis 寫入 redis 中。另外 SessionDAO 中可以使用 Cache 進行緩存,以提高性能。

8) CacheManager:緩存管理器。它來管理如用戶、角色、權限等的緩存的。因為這些數據基本上很少去改變,放到緩存中後可以提高訪問的性能。

9) Cryptography:密碼模塊,Shiro 提高了一些常見的加密組件用於如密碼加密/解密的。

5. Shiro 的基本入門

今天我們演示 Shiro 的入門,沒有整合任何框架,只是單純的演示 Shiro 運行原理,所以無需創建經典的五張表

5.1 使用 Idea 創建一個 Maven 項目

在 pom.xml 中添加如下依賴:

<code>
<dependencies>
<dependency>
<groupid>org.apache.shiro/<groupid>
<artifactid>shiro-core/<artifactid>
<version>1.2.3/<version>
/<dependency>
<dependency>
<groupid>org.slf4j/<groupid>
<artifactid>slf4j-simple/<artifactid>
<version>1.6.1/<version>
/<dependency>
/<dependencies>/<code>

5.2 任意創建一個包,在裡面創建一個測試的 Demo 類:

<code>package me.aihe;import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class Demo{
private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class); public static void main(String[] args) {
log.info("My First Apache Shiro Application"); System.exit(0);
}
}/<code>

5.3 創建一個 shiro.ini 配置文件


Shiro 提供了一個通用的方案通過 INI 進行配置 ,當然也可以通過 XML,YMAL,JSON 等進行配置。在 resource 目錄下面,創建一個 shiro.ini 的文件。內容如下:

<code># -------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -------------------------------------------------------------------------
[users]
root = secret, admin guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz aihe = aihe, goodguy, client
# -------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -------------------------------------------------------------------------
[roles] admin = *
client = look:*
goodguy = winnebago:drive:eagle5/<code>

5.4 引用 Shiro.ini 配置進行測試


現在改變我們的 Demo 類文件,內容如下

<code>import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Demo {
private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);
public static void main(String[] args) { log.info("My First Apache Shiro Application");
//1. 這裡的 SecurityManager 是 org.apache.shiro.mgt.SecurityManager,而不是
//java.lang.SecurityManager 加載配置文件

Factory<securitymanager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2.解析配置文件,並且返回一些 SecurityManger 實例
SecurityManager securityManager = factory.getInstance();
//3.設置 SecurityManager 到靜態內存區,單例模式
SecurityUtils.setSecurityManager(securityManager);
// 安全操作
Subject currentUser = SecurityUtils.getSubject();
// 在應用的當前會話中設置屬性
Session session = currentUser.getSession(); session.setAttribute("key","value");
//當前我們的用戶是匿名的用戶,我們嘗試進行登錄,
if(!currentUser.isAuthenticated()){
UsernamePasswordToken token = new UsernamePasswordToken("aihe", "aihe");
token.setRememberMe(true);
//嘗試進行登錄用戶,如果登錄失敗了,我們進行一些處理
try{ currentUser.login(token);
//當我們獲登錄用戶之後
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
// 查看用戶是否有指定的角色
if ( currentUser.hasRole( "client" ) ) {
log.info("Look is in your role" ); } else { log.info( ".\t" );
}
// 查看用戶是否有某個權限
if ( currentUser.isPermitted( "look:desk" ) ) {
log.info("You can look. Use it wisely.");
} else {
log.info("Sorry, you can't look.");
}
if ( currentUser.isPermitted( "winnebago:drive:eagle5" ) ) {
log.info("You are permitted to 'drive' the 'winnebago' with license plate (id) 'eagle5'. " + "Here are the keys - have fun!");
} else {
log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
}
//登出currentUser.logout()
} catch ( UnknownAccountException uae ) {
//賬戶不存在的操作
} catch ( IncorrectCredentialsException ice ) {
//密碼不正確

} catch ( LockedAccountException lae ) {
//用戶被鎖定了
} catch ( AuthenticationException ae ) {
//無法判斷的情形
}
}
System.exit(0); }
}/<securitymanager>/<code>

6. 通過 shiro 演示,我們學到了什麼

這個相對來說是一個簡單的程序,但也證明了一些 shiro 的基本用法,我們可以通過shiro 進行認證,權限控制等。

本文對 Shiro 進行了一個基本介紹,Shiro 具體在開發中的實際應用,以及更多在開發中的應用,我們並沒有具體說太多,比如和其它框架的整合等等,如果想對 Shiro 有更多的瞭解,請前往官網查閱。


分享到:


相關文章: