深入淺出Shiro系列

寫在前面:

小夥伴兒們,大家好!這次讓我們一起來學習Shiro權限框架吧!

思維導圖:

1,初識Shiro

1.1,簡介;

  • Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼和會話管理。使用Shiro的易於理解的API,您可以快速、輕鬆地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。

1.2,入門配置;

創建Maven工程命名爲Shiro,結構圖如下;

直接引入依賴:

<dependencies>

    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.5.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>2.0.0-alpha1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
    
  </dependencies>

log4j.properties配置文件:

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

# General Apache libraries
log4j.logger.org.apache=WARN

# Spring
log4j.logger.org.springframework=WARN

# Default Shiro logging
log4j.logger.org.apache.shiro=TRACE

# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

shiro.ini文件(放在resources目錄下),以鍵值對地形式存放:

[users]
java=123456
jack=123

1.3,程序文件;

我們新建一個HelloWorld類:

package com.java;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class HelloWorld {

    public static void main(String[] args) {
        // 讀取配置文件,初始化SecurityManager工廠
        Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
        // 獲取securityManager實例
        SecurityManager securityManager=factory.getInstance();
        // 把securityManager實例綁定到SecurityUtils
        SecurityUtils.setSecurityManager(securityManager);
        // 得到當前執行的用戶
        Subject currentUser=SecurityUtils.getSubject();
        // 創建token令牌,用戶名/密碼
        UsernamePasswordToken token=new UsernamePasswordToken("java", "123456");
        try{
            // 身份認證
            currentUser.login(token);
            System.out.println("身份認證成功!");
        }catch(AuthenticationException e){
            e.printStackTrace();
            System.out.println("身份認證失敗!");
        }
        // 退出
        currentUser.logout();
    }
}

  • 首先通過 new IniSecurityManagerFa ctory 並指定一個 ini 配置文件來創建一個 SecurityManager 工廠;

  • 接着獲取 SecurityManager 並綁定到 SecurityUtils,這是一個全局設置,設置一次即可;

  • 通過 SecurityUtils 得到 Subject,其會自動綁定到當前線程;如果在 web 環境在請求結束時需要解除綁定;然後獲取身份驗證的 Token,如用戶名 / 密碼;

  • 調用 subject.login 方法進行登錄,其會自動委託給 SecurityManager.lo gin 方法進行登錄;

  • 如果身份驗證失敗請捕獲 Authenticat ionException 或其子類,常見的如:DisabledAccountException(禁用的帳號)、LockedAccountException(鎖定的帳號)、UnknownAccountExceptio n(錯誤的帳號)、ExcessiveAttempts Exception(登錄失敗次數過多)、In correctCredentialsException (錯誤的憑證)、ExpiredCredentialsException (過期的憑證)等,具體請查看其繼承關係;對於頁面的錯誤消息展示,最好使用如 “用戶名 / 密碼錯誤” 而不是 “用戶名錯誤”/“密碼錯誤”,防止一些惡意用戶非法掃描帳號庫;

  • 最後可以調用 subject.logout 退出,其會自動委託給 SecurityManager.logout 方法退出。

運行:

從如上代碼可總結出身份驗證的步驟

  1. 收集用戶身份 / 憑證,即如用戶名 / 密碼;

  2. 調用 Subject.login 進行登錄,如果失敗將得到相應的 AuthenticationException 異常,根據異常提示用戶錯誤信息;否則登錄成功;

  3. 最後調用 Subject.logout 進行退出操作。

2,Shiro身份認證;

2.1,Subject認證主體;

在 shiro 中,用戶需要提供 principals (身份)和 credentials(證明)給 shiro,從而應用能驗證用戶身份:

principals:身份,即主體的標識屬性,可以是任何東西,如用戶名、郵箱等,唯一即可。一個主體可以有多個 principals ,但只有一個 Primary principals,一般是用戶名 / 密碼 / 手機號。

credentials:證明 / 憑證,即只有主體知道的安全值,如密碼 / 數字證書等。最常見的 principals 和 credentials 組合就是用戶名 / 密碼了。接下來先進行一個基本的身份認證。另外兩個相關的概念是之前提到的 SubjectRealm,分別是主體及驗證主體的數據源。

2.2,身份認證流程;

流程如下:

  1. 首先調用 Subject.login(token) 進行登錄,其會自動委託給 Security Manager ,調用之前必須通過 SecurityUtils.set SecurityManager() 設置;

  2. SecurityManager 負責真正的身份驗證邏輯;它會委託給 Authenticator 進行身份驗證;

  3. Authenticator 纔是真正的身份驗證者,Shiro API 中核心的身份認證入口點,此處可以自定義插入自己的實現;

  4. Authenticator 可能會委託給相應的 AuthenticationStrategy 進行多 Realm 身份驗證,默認 ModularRealmAuthen ticator 會調用 AuthenticationStrategy 進行多 Realm 身份驗證;

  5. Authenticator 會把相應的 token 傳入 Realm,從 Realm 獲取身份驗證信息,如果沒有返回 / 拋出異常表示身份驗證失敗了。此處可以配置多個 Realm,將按照相應的順序及策略進行訪問。

2.3,Realm;

Realm:域,Shiro 從從 Realm 獲取安全數據(如用戶、角色、權限),就是說 SecurityManager 要驗證用戶身份,那麼它需要從 Realm 獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從 Realm 得到用戶相應的角色 / 權限進行驗證用戶是否能進行操作;可以把 Realm 看成 DataSource,即安全數據源。如我們之前的 ini 配置方式將使用 org.apache.shiro .realm.text.IniRealm。

realm種類很多,例如常見的 jdbc realm,jndi realm,text realm,我們這裏就瞭解一下jdbc realm,其他的不做敘述;

  • 首先先建立數據庫db_shiro,然後添加表users(表名稱不可改),添加一條數據;

  • 配置文件jdbc_realm.ini,這與上文的shiro.ini是一樣的;

    [main]
    jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    dataSource=com.alibaba.druid.pool.DruidDataSource
    dataSource.driverClassName=com.mysql.jdbc.Driver
    dataSource.url=jdbc:mysql://localhost:3306/db_shiro
    dataSource.username=root
    dataSource.password=123456
    jdbcRealm.dataSource=$dataSource
    securityManager.realms=$jdbcRealm
    
  • 導入依賴

    <!-- mysql 數據庫及 druid 連接池-->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.25</version>
        </dependency>
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>0.2.23</version>
        </dependency>
    
  • 測試程序(把路徑更改一下即可)

    package com.java;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.Factory;
    
    public class JdbcRealmTest {
    
        public static void main(String[] args) {
            // 讀取配置文件,初始化SecurityManager工廠
            Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:jdbc_realm.ini");
            // 獲取securityManager實例
            SecurityManager securityManager=factory.getInstance();
            // 把securityManager實例綁定到SecurityUtils
            SecurityUtils.setSecurityManager(securityManager);
            // 得到當前執行的用戶
            Subject currentUser=SecurityUtils.getSubject();
            // 創建token令牌,用戶名/密碼
            UsernamePasswordToken token=new UsernamePasswordToken("java", "123");
            try{
                // 身份認證
                currentUser.login(token);
                System.out.println("身份認證成功!");
            }catch(AuthenticationException e){
                e.printStackTrace();
                System.out.println("身份認證失敗!");
            }
            // 退出
            currentUser.logout();
        }
    }
    
    
  • 運行結果


好了,今天就先分享到這裏了,下期繼續給大家帶來Shiro相關方面的學習!更多幹貨、優質文章,歡迎關注我的原創技術公衆號~

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