Apache 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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM