安全框架Shiro——Shiro簡介、架構、Quickstart程序

目錄


一、Shiro簡介

  • Apache Shiro 是 Java 的一個安全(權限)框架
  • Shiro 可以非常容易的開發出足夠好的應用,其不僅可以用在JavaSE 環境,也可以用在 JavaEE 環境。• Shiro 可以完成:認證、授權、加密、會話管理、與Web 集成、緩存等。
  • 下載: http://shiro.apache.org/
    在這裏插入圖片描述

1、功能簡介

跳轉到目錄
在這裏插入圖片描述

  • Authentication身份認證/(登錄),驗證用戶是不是擁有相應的身份;
  • Authorization授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限;即判斷用戶是否能進行什麼操作,如:驗證某個用戶是否擁有某個角色。或者細粒度的驗證某個用戶對某個資源是否具有某個權限;
  • Session Manager會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通 JavaSE 環境,也可以是 Web 環境的;
  • Cryptography加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲;
  • Web SupportWeb 支持,可以非常容易的集成到Web 環境;
  • Caching緩存,比如用戶登錄後,其用戶信息、擁有的角色/權限不必每次去查,這樣可以提高效率;
  • Concurrency:Shiro 支持多線程應用的併發驗證,即如在一個線程中開啓另一個線程,能
    把權限自動傳播過去;
  • Testing:提供測試支持;
  • Run As:允許一個用戶假裝爲另一個用戶(如果他們允許)的身份進行訪問;
  • Remember Me記住我,這個是非常常見的功能,即一次登錄後,下次再來的話不用登錄了

2、Shiro 架構

跳轉到目錄
外部來看Shiro ,即從應用程序角度的來觀察如何使用 Shiro 完成工作:
在這裏插入圖片描述

  • Subject應用代碼直接交互的對象是 Subject,也就是說 Shiro 的對外API 核心就是 Subject。Subject 代表了當前“用戶”, 這個用戶不一定是一個具體的人,與當前應用交互的任何東西都是 Subject,如網絡爬蟲,機器人等;與 Subject 的所有交互都會委託給 SecurityManager;Subject 其實是一個門面,SecurityManager 纔是實際的執行者
  • SecurityManager安全管理器;即所有與安全有關的操作都會與SecurityManager 交互;且其管理着所有 Subject;可以看出它是 Shiro的核心,它負責與 Shiro 的其他組件進行交互,它相當於 SpringMVC 中DispatcherServlet 的角色
  • RealmShiro 從 Realm 獲取安全數據(如用戶、角色、權限),就是說SecurityManager 要驗證用戶身份,那麼它需要從 Realm 獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從 Realm 得到用戶相應的角色/權限進行驗證用戶是否能進行操作;可以把 Realm 看成 DataSource

內部來看Shiro架構

在這裏插入圖片描述

  • Subject:任何可以與應用交互的“用戶”
  • SecurityManager :相當於SpringMVC 中的 DispatcherServlet;是 Shiro 的心臟;所有具體的交互都通過 SecurityManager 進行控制;它管理着所有 Subject、且負責進行認證、授權、會話及緩存的管理。
  • Authenticator負責 Subject 認證,是一個擴展點,可以自定義實現;可以使用認證策略(Authentication Strategy),即什麼情況下算用戶認證通過了;
  • Authorizer授權器、即訪問控制器,用來決定主體是否有權限進行相應的操作;即控制着用戶能訪問應用中的哪些功能;
  • Realm:可以有 1 個或多個 Realm,可以認爲是安全實體數據源,即用於獲取安全實體的;可以是JDBC 實現,也可以是內存實現等等;由用戶提供;所以一般在應用中都需要實現自己的 Realm
  • SessionManager管理 Session 生命週期的組件;而 Shiro 並不僅僅可以用在 Web 環境,也可以用在如普通的 JavaSE 環境
  • CacheManager:緩存控制器,來管理如用戶、角色、權限等的緩存的;因爲這些數據基本上很少改變,放到緩存中後可以提高訪問的性能
  • Cryptography密碼模塊,Shiro 提高了一些常見的加密組件用於如密碼加密/解密。

二、Shiro的HelloWorld程序

跳轉到目錄
首先創建一個普通的maven項目

1、在官網/github中下載最新穩定版的"zip"壓縮包,打開之後找到之中的示例文件夾"samples"

在這裏插入圖片描述
將上圖中resources中的log4j的配置文件shiro.ini文件拷到項目的resources下, 將java中的Quickstart.java拷貝到我們的項目中;

2、導入pom.xml中的座標
<dependencies>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.5.2</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.25</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>

    <!-- shiro默認使用的日誌框架是, commons-logging -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>
3、shiro.ini、log4j.properties文件

shiro.ini文件
在這裏插入圖片描述

log4j.properties文件
在這裏插入圖片描述

3、Quickstart類的分析

跳轉到目錄

/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {

    // 使用日誌門面
    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);

    public static void main(String[] args) {

        // 從classpath路徑下, 加載shiro.ini文件,創建一個生產SecurityManager工廠
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        // 通過這個工程生產SecurityManager實例
        SecurityManager securityManager = factory.getInstance();

        SecurityUtils.setSecurityManager(securityManager);

        // 獲取當前的用戶對象subject
        Subject currentUser = SecurityUtils.getSubject();

        // 通過當前用戶拿到shiro的session--測試session
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "桂朝陽");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("桂朝陽")) {
            log.info("Retrieved the correct value! [" + value + "]");
        }

        // 判斷當前的用戶是否被認證(即是否已經登錄)
        if (!currentUser.isAuthenticated()) {
            // 沒有登錄,把用戶名和密碼封裝爲UsernamePasswordToken對象
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true); // 設置記住我
            try {
            	// 執行登錄,上面token中的用戶名密碼在shiro.ini中已經配置,可以登錄成功
                currentUser.login(token);
            } catch (UnknownAccountException uae) { // 用戶不存在的異常
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {   // 密碼錯誤異常
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {  // 用戶鎖定異常
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // 所有認證時異常的父類
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        // 獲取當前用戶名稱(這裏是lonestarr,已經存在了,在shiro.ini中)
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        // 當前用戶是否有`schwartz`這個角色(可以在shiro.ini中看到,`lonestarr`用戶有這個角色
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }

        // 粗粒度的訪問某資源(可以看shiro.ini中第二種角色: 訪問權限分的不是很細緻)
        // 判斷當前用戶是否擁有"lightsaber:wield"權限
        if (currentUser.isPermitted("lightsaber:wield")) {
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        // 細粒度 (可以看shiro.ini中第三種角色: 訪問權限分的比較細緻)
        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();

        // 結束
        System.exit(0);
    }
}

在這裏插入圖片描述

總結:

// 獲取當前的用戶對象subject
Subject currentUser = SecurityUtils.getSubject();
//使用Session做一些操作,此時不需要web容器也可以進行
Session session = currentUser.getSession();
// 判斷當前的用戶是否被認證(是否已經登錄)
currentUser.isAuthenticated();
// 獲取當前用戶名稱(這裏是lonestarr,已經存在了,在shiro.ini中)
currentUser.getPrincipal();
// 當前用戶是否有schwartz這個角色
currentUser.hasRole(“schwartz”);
// 判斷當前用戶是否擁有"lightsaber:wield"權限
currentUser.isPermitted(“lightsaber:wield”);
// 註銷
currentUser.logout();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章