Apache Shiro(一)-登錄認證和許可權管理初識

来源:https://www.cnblogs.com/fengyuduke/archive/2019/02/19/10400843.html
-Advertisement-
Play Games

What is Apache Shiro? Apache Shiro是一個功能強大、靈活的,開源的安全框架。它可以乾凈利落地處理身份驗證、授權、企業會話管理和加密。 Apache Shiro的首要目標是易於使用和理解。安全通常很複雜,甚至讓人感到很痛苦,但是Shiro卻不是這樣子的。一個好的安全框架 ...


What is Apache Shiro?

Apache Shiro是一個功能強大、靈活的,開源的安全框架。它可以乾凈利落地處理身份驗證、授權、企業會話管理和加密。

Apache Shiro的首要目標是易於使用和理解。安全通常很複雜,甚至讓人感到很痛苦,但是Shiro卻不是這樣子的。一個好的安全框架應該屏蔽複雜性,向外暴露簡單、直觀的API,來簡化開發人員實現應用程式安全所花費的時間和精力。

Shiro能做什麼呢?

  • 驗證用戶身份
  • 用戶訪問許可權控制,比如:1、判斷用戶是否分配了一定的安全形色。2、判斷用戶是否被授予完成某個操作的許可權
  • 在非 web 或 EJB 容器的環境下可以任意使用Session API
  • 可以響應認證、訪問控制,或者 Session 生命周期中發生的事件
  • 可將一個或以上用戶安全數據源數據組合成一個複合的用戶 "view"(視圖)
  • 支持單點登錄(SSO)功能
  • 支持提供“Remember Me”服務,獲取用戶關聯信息而無需登錄

等等——都集成到一個有凝聚力的易於使用的API。

Shiro 致力在所有應用環境下實現上述功能,小到命令行應用程式,大到企業應用中,而且不需要藉助第三方框架、容器、應用伺服器等。當然 Shiro 的目的是儘量的融入到這樣的應用環境中去,但也可以在它們之外的任何環境下開箱即用。

Apache Shiro Features 特性

Apache Shiro是一個全面的、蘊含豐富功能的安全框架。下圖為描述Shiro功能的框架圖:

Authentication(認證), Authorization(授權), Session Management(會話管理), Cryptography(加密)被 Shiro 框架的開發團隊稱之為應用安全的四大基石。那麼就讓我們來看看它們吧:

  • Authentication(認證):用戶身份識別,通常被稱為用戶“登錄”
  • Authorization(授權):訪問控制。比如某個用戶是否具有某個操作的使用許可權。
  • Session Management(會話管理):特定於用戶的會話管理,甚至在非web 或 EJB 應用程式。
  • Cryptography(加密):在對數據源使用加密演算法加密的同時,保證易於使用。

還有其他的功能來支持和加強這些不同應用環境下安全領域的關註點。特別是對以下的功能支持:

  • Web支持:Shiro 提供的 web 支持 api ,可以很輕鬆的保護 web 應用程式的安全。
  • 緩存:緩存是 Apache Shiro 保證安全操作快速、高效的重要手段。
  • 併發:Apache Shiro 支持多線程應用程式的併發特性。
  • 測試:支持單元測試和集成測試,確保代碼和預想的一樣安全。
  • "Run As":這個功能允許用戶假設另一個用戶的身份(在許可的前提下)。
  • "Remember Me":跨 session 記錄用戶的身份,只有在強制需要時才需要登錄。

註意: Shiro不會去維護用戶、維護許可權,這些需要我們自己去設計/提供,然後通過相應的介面註入給Shiro。

High-Level Overview 高級概述

在概念層,Shiro 架構包含三個主要的理念:Subject,SecurityManager和 Realm。下麵的圖展示了這些組件如何相互作用,我們將在下麵依次對其進行描述。

  • Subject:當前用戶,Subject 可以是一個人,但也可以是第三方服務、守護進程帳戶、時鐘守護任務或者其它--當前和軟體交互的任何事件。
  • SecurityManager:管理所有Subject,SecurityManager 是 Shiro 架構的核心,配合內部安全組件共同組成安全傘。
  • Realms:用於進行許可權信息的驗證,我們自己實現。Realm 本質上是一個特定的安全 DAO:它封裝與數據源連接的細節,得到Shiro 所需的相關的數據。在配置 Shiro 的時候,你必須指定至少一個Realm 來實現認證(authentication)和/或授權(authorization)。

我們需要實現Realms的Authentication 和 Authorization。其中 Authentication 是用來驗證用戶身份,Authorization 是授權訪問控制,用於對用戶進行的操作授權,證明該用戶是否允許進行當前操作,如訪問某個鏈接,某個資源文件等。


 

快速上手

第一步:

話不多說,我們先構建一個最簡單的項目,結構如下:

 

 第二步:

編輯shiro.ini

這裡面定義了和安全相關的數據: 用戶,角色和許可權
註釋很詳細了,挨個看就能理解了

#定義用戶
[users]
#用戶名 zhang3  密碼是 12345, 角色是 admin
zhang3 = 12345, admin
#用戶名 li4  密碼是 abcde, 角色是 產品經理
li4 = abcde,productManager
#定義角色
[roles]
#管理員什麼都能做
admin = *
#產品經理只能做產品管理
productManager = addProduct,deleteProduct,editProduct,updateProduct,listProduct
#訂單經理只能做訂單管理
orderManager = addOrder,deleteOrder,editOrder,updateOrder,listOrder

 

第三步:

準備用戶類User,用於存放賬號密碼

public class User {

    private String name;
    private String password;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
}

 

第四步:

編輯TestShiro 

準備3個用戶,前兩個能在 shiro.ini 中找到,第3個不存在
然後測試登錄
接著測試是否包含角色
最後測試是否擁有許可權

註:Subject 在 Shiro 這個安全框架下, Subject 就是當前用戶

 

  1 public class TestShiro {
  2     public static void main(String[] args) {
  3         //用戶們
  4         User zhang3 = new User();
  5         zhang3.setName("zhang3");
  6         zhang3.setPassword("12345");
  7 
  8         User li4 = new User();
  9         li4.setName("li4");
 10         li4.setPassword("abcde");
 11         
 12         
 13         User wang5 = new User();
 14         wang5.setName("wang5");
 15         wang5.setPassword("wrongpassword");
 16 
 17         List<User> users = new ArrayList<>();
 18         
 19         users.add(zhang3);
 20         users.add(li4);
 21         users.add(wang5);        
 22         //角色們
 23         String roleAdmin = "admin";
 24         String roleProductManager ="productManager";
 25         
 26         List<String> roles = new ArrayList<>();
 27         roles.add(roleAdmin);
 28         roles.add(roleProductManager);
 29         
 30         //許可權們
 31         String permitAddProduct = "addProduct";
 32         String permitAddOrder = "addOrder";
 33         
 34         List<String> permits = new ArrayList<>();
 35         permits.add(permitAddProduct);
 36         permits.add(permitAddOrder);
 37         
 38         
 39         
 40         
 41 
 42         //登陸每個用戶
 43         for (User user : users) {
 44             if(login(user)) 
 45                 System.out.printf("%s \t成功登陸,用的密碼是 %s\t %n",user.getName(),user.getPassword());
 46             else 
 47                 System.out.printf("%s \t成功失敗,用的密碼是 %s\t %n",user.getName(),user.getPassword());
 48         }
 49         
 50         
 51         System.out.println("-------how2j 分割線------");
 52         
 53         //判斷能夠登錄的用戶是否擁有某個角色
 54         for (User user : users) {
 55             for (String role : roles) {
 56                 if(login(user)) {
 57                     if(hasRole(user, role)) 
 58                         System.out.printf("%s\t 擁有角色: %s\t%n",user.getName(),role);
 59                     else
 60                         System.out.printf("%s\t 不擁有角色: %s\t%n",user.getName(),role);
 61                 }
 62             }    
 63         }
 64         System.out.println("-------how2j 分割線------");
 65 
 66         //判斷能夠登錄的用戶,是否擁有某種許可權
 67         for (User user : users) {
 68             for (String permit : permits) {
 69                 if(login(user)) {
 70                     if(isPermitted(user, permit)) 
 71                         System.out.printf("%s\t 擁有許可權: %s\t%n",user.getName(),permit);
 72                     else
 73                         System.out.printf("%s\t 不擁有許可權: %s\t%n",user.getName(),permit);
 74                 }
 75             }    
 76         }
 77     }
 78     
 79     private static boolean hasRole(User user, String role) {
 80         Subject subject = getSubject(user);
 81         return subject.hasRole(role);
 82     }
 83     
 84     private static boolean isPermitted(User user, String permit) {
 85         Subject subject = getSubject(user);
 86         return subject.isPermitted(permit);
 87     }
 88 
 89     private static Subject getSubject(User user) {
 90         //載入配置文件,並獲取工廠
 91         Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
 92         //獲取安全管理者實例
 93         SecurityManager sm = factory.getInstance();
 94         //將安全管理者放入全局對象
 95         SecurityUtils.setSecurityManager(sm);
 96         //全局對象通過安全管理者生成Subject對象
 97         Subject subject = SecurityUtils.getSubject();
 98 
 99         return subject;
100     }
101     
102     
103     private static boolean login(User user) {
104         Subject subject= getSubject(user);
105         //如果已經登錄過了,退出
106             
107             if(subject.isAuthenticated()) {
108                 
109                 subject.logout();
110         }
111         
112         //封裝用戶的數據
113         UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword());
114         try {
115             //將用戶的數據token 最終傳遞到Realm中進行對比
116             subject.login(token);
117         } catch (AuthenticationException e) {
118             //驗證錯誤
119             return false;
120         }                
121         
122         return subject.isAuthenticated();
123     }
124     
125     
126     
127     
128 }
代碼行數較多,點擊展開

 

 第五步:

運行 TestShiro,可以觀察到如圖所示的效果
某個用戶是否登陸成功
某個用戶是否擁有某個角色
某個用戶是否擁有某種許可權

最後

代碼下載地址:https://gitee.com/fengyuduke/my_open_resources/blob/master/shiro.rar

在這裡,賬號密碼,角色信息都是放在配置文件里的,真實工作的時候,肯定都是放在資料庫里的。那麼怎麼做呢?請看下期!!! 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 2. ...
  • 判斷以下代碼的執行結果(涉及變數提升,函數聲明,原型鏈,this指向,作用域等知識點) "掘金" 上看到的一個筆試題目,記錄並分析總結以下考察點。 第一個 不用說什麼,直接調用Foo構造函數的getName屬性,輸出2。 第二個 調用當前作用域下的getName函數,要註意 函數表達式 和 函數聲明 ...
  • 數組的方法 數組的的大部分方法都可以實現數組的遍歷。 foreach方法 實現數組的遍歷 map方法 map方法的作用:會生成一個與遍歷對象數組相同長度的新數組,並且map中的返回值就是新數組的參數值。 filter方法 過濾,起到篩選的作用。 find方法 includes方法 some方法和ar ...
  • 今天突然看到一篇關於CSS中盒模型的文章,忽然覺得自己竟然遺忘了很多小的地方,所以寫一篇文章來記憶一下 (摘抄於千與千尋寫的CSS盒子模型理解,併在自己基礎上添加了一些東西,希望更完善,對大家有幫助) 1.基本的盒模型知識 CSS css盒子模型 又稱框模型 (Box Model) ,包含了元素內容 ...
  • 靜態資源的請求和載入速度,直接影響頁面呈現,應該怎麼優化呢? ...
  • 程式的冪等性,概念:一個函數執行多次皆返回相同的結果。作用:一個函數被調用多次時,保證內部狀態的一致性 ...
  • mock有兩種使用方式,一種是僅編寫數據來調用,第二種是編寫 服務+數據模擬真實介面(可在network查看) ...
  • 話不多說,現在在開發微服務項目,也想系統的學習一下SpringCloud,顧選擇硬著頭皮跟著英文官方文檔學習一遍SpringCloud。 現在公司在用SpringCloud,也有很好的實踐應用,加上更加系統的學習,不知道結果會怎樣,至少自己努力過,就不會後悔! 接下來開始SpringCloud的學習 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...