Shiro(Java權限框架)入門


什么是Shiro?

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

shiro不依賴於spring,shiro不僅可以實現 web應用的權限管理,還可以實現c/s系統,分布式系統權限管理,shiro屬於輕量框架,越來越多企業項目開始使用shiro。

Shiro組成部分

  • subject:主體,可以是用戶也可以是程序,主體要訪問系統,系統需要對主體進行認證、授權。
  • securityManager:安全管理器,主體進行認證和授權都是通過securityManager進行。securityManager是一個集合,真正做事的不是securityManager而是它里面的東西。
  • authenticator:認證器,主體進行認證最終通過authenticator進行的。
  • authorizer:授權器,主體進行授權最終通過authorizer進行的。
  • sessionManager:web應用中一般是用web容器(中間件tomcat)對session進行管理,shiro也提供一套session管理的方式。
  • shiro不僅僅可以用於web管理也可以用於cs管理,所以他不用web容器的session管理。
  • SessionDao: 通過SessionDao管理session數據,針對個性化的session數據存儲需要使用sessionDao(如果用tomcat管理session就不用SessionDao,如果要分布式的統一管理session就要用到SessionDao)。
  • cache Manager:緩存管理器,主要對session和授權數據進行緩存(權限管理框架主要就是對認證和授權進行管理,session是在服務器緩存中的),比如將授權數據通過cacheManager進行緩存管理,和ehcache整合對緩存數據進行管理(redis是緩存框架)。
  • realm:域,領域,相當於數據源,通過realm存取認證、授權相關數據(原來是通過數據庫取的)。注意:authenticator認證器和authorizer授權器調用realm中存儲授權和認證的數據和邏輯。
  • cryptography:密碼管理,比如md5加密,提供了一套加密/解密的組件,方便開發。比如提供常用的散列、加/解密等功能。比如 md5散列算法(md5只有加密沒有解密)。

核心組件

在shiro中核心的概念有三個:

1.subject

即“當前操作用發戶”。但是,在Shiro中,Subject這一概念並不僅僅指人,也可以是第三方進程(比如微信QQ等等)、后台帳戶(Daemon Account)或其他類似事物。它僅僅意味着“當前跟軟件交互的東西”。但考慮到大多數目的和用途,你可以把它認為是Shiro的“用戶”概念。Subject代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作。

2.Security Manager

它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,並通過它來提供安全管理的各種服務,且它管理着所有Subject;可以看出它是Shiro 的核心,它負責與后邊介紹的其他組件進行交互,如果學習過SpringMVC,你可以把它看成DispatcherServlet前端控制器。

3.Realm

       域,Shiro從從Realm獲取安全數據(如用戶、角色、權限),就是說SecurityManager要驗證用戶身份,那么它需要從Realm獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從Realm得到用戶相應的角色/權限進行驗證用戶是否能進行操作;可以把Realm看成DataSource,即安全數據源,同時也可以是配置文件。

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

Shiro 特點

(1)易於理解的 Java Security API;
(2)簡單的身份認證(登錄),支持多種數據源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
(3)對角色的簡單的簽權(訪問控制),支持細粒度的簽權;
(4)支持一級緩存,以提升應用程序的性能;
(5)內置的基於 POJO 企業會話管理,適用於 Web 以及非 Web 的環境;
(6)異構客戶端會話訪問;
(7)非常簡單的加密 API,自帶的加密API完全夠用;
(8)不跟任何的框架或者容器捆綁,可以獨立運行

實現簡單案例

1.添加依賴:

        <!-- shiro核心包 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!-- 添加shiro web支持 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>

2.添加安全數據源shiro-permission.ini文件(官方推薦使用ini文件格式):

[users]
zs=123,role1,role2,role3
ls=123,role2
ww=123,role3
admin=123,role1,role2,role3,admin


[roles]
role1=user:create,user:update,user:delete,user:view,user:load
role2=user:create,user:delete
role3=user:create
admin=user:*

3.添加Demo測試類:

package com.star.demo;

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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Demo {

    public static void main(String[] args) {

        //org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token 密碼錯誤認證失敗
        //org.apache.shiro.authc.UnknownAccountException: Realm [org.apache.shiro...] was unable to find account data
        // 賬戶不存在錯誤

        //1:獲取securityFactory工廠類
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro" +
                "-permission" +
                ".ini");
        //2.獲取安全管理器對象
        SecurityManager instance = iniSecurityManagerFactory.getInstance();
        //3.設置subjectManager對象,把subjec對象交給SecurityUtils管理
        SecurityUtils.setSecurityManager(instance);
        //4.獲取subject對象
        Subject subject = SecurityUtils.getSubject();
        //5.生成token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin","123");
        //6.進行驗證
        try {
            //7.登陸(身份認證)
            subject.login(usernamePasswordToken);
            System.out.println("身份認證成功!");
        } catch (AuthenticationException e) {
            e.printStackTrace();
            System.out.println("身份認證失敗!");
        }

        //8.用戶授權
        try {
//            if(subject.hasRole("role6")){//1.普通授權方式,檢查單個授權
            //2.傳集合用戶授權,有一個未授權的就返回false
//            List<String> list= new ArrayList<>();
//            list.add("role1");
//            list.add("role6");
//            list.add("role3");
//            if(subject.hasAllRoles(list)){//傳集合判斷權限
            //3.hasRoles方式判斷權限
            boolean[] booleans = subject.hasRoles(Arrays.asList("role1", "role2", "role3"));
            boolean f = false;
            int n = 0;
            for (int i = booleans.length - 1; i >= 0; i--) {
                if(booleans[i])
                    ++n;
                if(n==booleans.length){
                    f = true;
                    break;
                }
            }
            if(f){
                System.out.println("用戶授權成功!");
            }else {
                System.out.println("用戶未授權!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //9.check方式檢查授權,未授權直接報錯
        try {
            //1.checkRole方式不存在權限直接報錯org.apache.shiro.authz.UnauthorizedException: Subject does not have role [role7]
//            subject.checkRole("role7");
            //2.checkRoles方式不存在直接報錯,可以傳可變的String參數或者是數組
            subject.checkRoles(Arrays.asList("role1","role2","role3"));
            subject.checkRoles("role1","role2","role3");
            System.out.println("用戶已授權~");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("用戶未授權!");
        }

        //10.permission方式檢查權限
        try {
//            //isPermitted可以接受String可變參數,集合等
//            if(subject.isPermitted("user:*"))
//                System.out.println("用戶已授權!");
//            else
//                System.out.println("用戶未授權!");
            //checkPermitted方式(*代表所有權限不管權限是否存在)
            subject.checkPermission("user:234234");
            System.out.println("用戶已授權!");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("用戶未授權!");
        }


    }

}


免責聲明!

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



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