走進shiro,構建安全的應用程式---shiro修仙序章

0. 寫在前面

在最近的一個項目當中,我們基於Shiro實現我們系統的認證和授權。藉此機會,寫幾篇部落格,總結一下在本次實踐當中遇到的問題,和較全面地學習一下Shiro的知識點,

1. 許可權管理

許可權管理實現對用戶訪問系統的控制,按照安全規則或者安全策略控制用戶訪問而且只能訪問授權訪問的資源。

許可權管理主要分為兩個部分,一是身份認證(authentication),二是授權(authorization)。

2. 實現方案與模型

目前主流的解決方案spring security+JWT或者Shiro+JWT方案。當然也有相關團隊(公司)是自己編寫過濾器進行訪問控制。但這並不值得推薦,除非你設計的許可權管理方案能經得起生產環境的考驗。

如果大家需要了解關於spring security的相關內容,可以閱讀我spring security的相關文章。

許可權管理模型的話,主要有這麼幾種:

  1. 自主訪問控制(DAC: Discretionary Access Control)。一個典型的例子就是windows作業系統的許可權管理。DAC 最大的缺陷就是對許可權控制比較分散,不便於管理,比如說簡單地對一組文件設置統一的許可權並授予指定的一組用戶。

  2. 強制訪問控制模型(MAC: Mandatory Access Control)。MAC為了彌補DAC而生,MAC給用戶和資源分別數字化標記其許可權等級。當用戶訪問某一資源時,只有它的許可權等級高於或等於資源的許可權等級時,才能訪問,否則拒絕訪問。比如存在某一資源404.MP4,資源等級為1024.存在用戶Ferrayman,其許可權等級為256,存在用戶boss,其許可權等級為2048.那麼,boss就能正常訪問資源404.MP4,而Ferrayman則無權訪問。

  3. 基於角色的訪問控制模型(RBAC: Role-based Access Control),即給用戶分配角色,角色下對應一定的資源,用戶對其角色下的資源具有訪問許可權。RBAC細分為RBAC0、RBAC1、RBAC2、RBAC3幾個版本。

    ​

    我們主要採用的也是RBAC模型。

3. Shiro是什麼?

Apache Shiro™ is a powerful and easy-to-use Java security framework that performs 
authentication, authorization, cryptography, and session management. With Shiro』s 
easy-to-understand API, you can quickly and easily secure any application – from the 
smallest mobile applications to the largest web and enterprise applications.

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

3.1 Shiro組成

Shiro三大組件:Subject, SecurityManager 和 Realms.

3.1.1 Subject:

即「當前主體」。在Shiro中,Subject這一概念並不僅僅指人,也可以是第三方進程、後台帳戶(Daemon Account)或其他類似事物。它僅僅意味著「當前跟軟體交互的東西」。Subject代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作。

它主要由身份資訊Principal和憑證Principals組成。Principal可以理解為主體在系統中的帳號,且是具有唯一性的。Principals可以理解為主體在當前系統賬戶所對應的密碼、證書。

3.1.2 SecurityManager:

它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,並通過它來提供安全管理的各種服務。

3.1.3 Realm:

Realm充當了Shiro與應用安全數據間的「橋樑」或者「連接器」。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其許可權資訊。

從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了數據源的連接細節,並在需要時將相關數據提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用於認證和(或)授權。配置多個Realm是可以的,但是至少需要一個。

Shiro內置了可以連接大量安全數據源(又名目錄)的Realm,如LDAP、關係資料庫(JDBC)、類似INI的文本配置資源以及屬性文件等。如果預設的Realm不能滿足需求,你還可以插入代表自定義數據源的自己的Realm實現。

4 Shiro的優勢

簡單、靈活。

使用起來相對於spring security簡單。不僅支援Web應用也支援非Web應用,無縫集成。

5 一個Demo

創建一個空的maven工程並引入如下依賴

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.5.3</version>
</dependency>
<!--方便測試-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
     <scope>test</scope>
</dependency>

引入shiro的配置文件

shiro的配置文件是以「.ini」結尾的文件。之所以使用.ini格式,是因為該文件類型支援比較複雜的數據格式。主要用來存儲shiro的一些許可權數據。這個主要是拿來學習shiro用的,平時項目中,許可權數據存儲於資料庫中。

配置主體的身份資訊和憑證

[users]
xiangbei=123
xiangname=123

創建認證器

package pers.lbf.shirodemo.core;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

/**認證器
 * @author 賴柄灃 [email protected]
 * @version 1.0
 * @date 2020/9/21 0:50
 */
public class Authenticator {

    private DefaultSecurityManager securityManager;

    public Authenticator(){
        //1. 創建安全管理器
        this.securityManager = new DefaultSecurityManager();

        //2. 給安全管理器設置問題域
        //因為許可權資訊從ini文件中讀取,所以是IniRealm
        this.securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

        //3. 注入安全管理器,並使用SecurityUtils全局安全工具類完成認證
        SecurityUtils.setSecurityManager(securityManager);



    }

    /**認證
     * @author 賴柄灃 [email protected]
     * @date 2020-09-23 16:22:11
     * @param username 用戶名
     * @param password 密碼
     * @return void
     * @version 1.0
     */
    public void authenticate(String username,String password){
        //4. 獲取當前主題
        Subject subject = SecurityUtils.getSubject();

        //5.根據登錄對象身份憑證資訊創建登錄令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

        //6.認證
        //如果認證通過,則不拋出異常,否則拋出AuthenticationExceptixon異常子類
        //正式項目建議直接拋出,統一異常處理
        try {
            subject.login(token);
        }catch (IncorrectCredentialsException e) {
            e.printStackTrace();
        }catch (ConcurrentAccessException e){
            e.printStackTrace();
        }catch (UnknownAccountException e){
            e.printStackTrace();
        }catch (ExcessiveAttemptsException e){
            e.printStackTrace();
        }catch (ExpiredCredentialsException e){
            e.printStackTrace();
        }catch (LockedAccountException e){
            e.printStackTrace();
        }

    }


}

測試,模擬認證

package shirodemo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
import pers.lbf.shirodemo.core.Authenticator;

/**測試認證
 * @author 賴柄灃 [email protected]
 * @version 1.0
 * @date 2020/9/21 0:49
 */

public class TestAuthenticator {
    private  Authenticator authenticator=null;

    @Before
    public void init() {
        authenticator = new Authenticator();
    }

    @Test
    public void testAuth(){

        authenticator.authenticate("xiangbei","123");
    }
}

6 寫在最後

今天,我們主要通過一個簡單的demo,去開始學習shiro的相關知識。但這些知識還不足以讓我們應用到我們的產品中去,接下來的shiro系列修仙功法(文章),作者將跟著大家一起去學習shiro的應用。

Tags: