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

code81192發表於2020-10-04

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 賴柄灃 bingfengdev@aliyun.com
 * @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 賴柄灃 bingfengdev@aliyun.com
     * @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 賴柄灃 bingfengdev@aliyun.com
 * @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的應用。

相關文章