1、shiro簡介
1.1、概述
Apache Shiro 是一個功能強大且易于使用的 Java 安全(權限)框架。Shiro 可以完成:認證、授權、加密、會話管理、與 Web 集成、緩存 等。借助 Shiro 您可以快速輕松地保護任何應用程序——從最小的移動應用程序到最大的 Web 和企業(yè)應用程序。
官網:https://shiro.apache.org/
1.2、為什么要用 Shiro
自 2003 年以來,框架格局發(fā)生了相當大的變化,因此今天仍然有很多系統(tǒng)在使用Shiro。這與 Shiro 的特性密不可分。
- 易于使用:使用 Shiro 構建系統(tǒng)安全框架非常簡單。就算第一次接觸也可以快速掌 握。
- 全面:Shiro 包含系統(tǒng)安全框架需要的功能,滿足安全需求的“一站式服務”。
- 靈活:Shiro 可以在任何應用程序環(huán)境中工作。雖然它可以在 Web、EJB 和 IoC 環(huán)境 中工作,但不需要依賴它們。Shiro也沒有強制要求任何規(guī)范,甚至沒有很多依賴項。
- 強力支持 Web:Shiro 具有出色的 Web 應用程序支持,可以基于應用程序 URL 和 Web 協(xié)議(例如REST)創(chuàng)建靈活的安全策略,同時還提供一組 JSP 庫來控制頁面輸出。
- 兼容性強:Shiro 的設計模式使其易于與其他框架和應用程序集成。Shiro 與Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin 等框架無縫集成。
- 社區(qū)支持:Shiro 是 Apache 軟件基金會的一個開源項目,有完備的社區(qū)支持,文檔 支持。如果需要,像 Katasoft 這樣的商業(yè)公司也會提供專業(yè)的支持和服務。
1.3、Shiro 與 SpringSecurity 的對比
- Spring Security 基于 Spring 開發(fā),項目若使用 Spring 作為基礎,配合 Spring Security做權限更加方便,而 Shiro 需要和 Spring 進行整合開發(fā);
- Spring Security 功能比 Shiro 更加豐富些,例如安全維護方面;
- Spring Security 社區(qū)資源相對比 Shiro 更加豐富;
- Shiro 的配置和使用比較簡單,Spring Security 上手復雜些;
- Shiro 依賴性低,不需要任何框架和容器,可以獨立運行。Spring Security 依賴 Spring 容器;
- shiro 不僅僅可以使用在 web 中,它可以工作在任何應用環(huán)境中。在集群會話時 Shiro最重要的一個好處或許就是它的會話是獨立于容器的。
1.4、基本功能
- Authentication:身份認證/登錄,驗證用戶是不是擁有相應的身份。
- Authorization:授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限;即 判斷用戶是否能進行什么操作,如:驗證某個用戶是否擁有某個角色?;蛘呒毩6鹊尿炞C 某個用戶 對某個資源是否具有某個權限。
- Session Manager:會話管理,即用戶登錄后就是一次會話,在沒有退出之前,它的 所有 信息都在會話中;會話可以是普通JavaSE 環(huán)境,也可以是 Web 環(huán)境的。
- Cryptography:加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲。
- Web Support:Web 支持,可以非常容易的集成到 Web 環(huán)境。
- Caching:緩存,比如用戶登錄后,其用戶信息、擁有的角色/權限不必每次去查,這 樣可 以提高效率。
- Concurrency:Shiro 支持多線程應用的并發(fā)驗證,即如在一個線程中開啟另一個線程,能把權限自動傳播過去。
- Testing:提供測試支持。
- Run As:允許一個用戶假裝為另一個用戶(如果他們允許)的身份進行訪問。
- Remember Me:記住我,這個是非常常見的功能,即一次登錄后,下次再來的話不用登錄了。
1.5、原理
1.5.1、Shiro 架構(Shiro 外部來看)
從外部來看 Shiro ,即從應用程序角度的來觀察如何使用 Shiro 完成工作Shiro 架構
- Subject:應用代碼直接交互的對象是 Subject,也就是說 Shiro 的對外 API 核心 就是Subject。Subject 代表了當前“用戶”, 這個用戶不一定是一個具體的人,與當前應用交互的任何東西都是Subject,如網絡爬蟲, 機器人等;與 Subject 的所有交互 都會委托給 SecurityManager; Subject其實是一個門面,SecurityManager 才是實際的執(zhí)行者。
- SecurityManager:安全管理器;即所有與安全有關的操作都會與 SecurityManager 交互;且其管理著所有Subject;可以看出它是 Shiro 的核心,它負責與 Shiro 的其他 組件進行交互,它相當于 SpringMVC 中DispatcherServlet 的角色。
- Realm:Shiro 從 Realm 獲取安全數據(如用戶、角色、權限),就是說 SecurityManager 要驗證用戶身份,那么它需要從 Realm 獲取相應的用戶 進行比較以確 定用戶身份是否合法;也需要從 Realm 得到用戶相應的角色/權限進行驗證用戶是否能進 行操作;可以把 Realm 看成 DataSource。
1.5.2、Shiro 架構(Shiro 內部來看)
Shiro 架構
- Subject:任何可以與應用交互的“用戶”。
- SecurityManager :相當于 SpringMVC 中的 DispatcherServlet;是 Shiro 的心臟;所有具體的交互都通過 SecurityManager 進行控制;它管理著所有 Subject、且負 責進行認證、授權、會話及緩存的管理。
- Authenticator:負責 Subject 認證,是一個擴展點,可以自定義實現;可以使用認證策略(Authentication Strategy),即什么情況下算用戶認證通過了。
- Authorizer:授權器、即訪問控制器,用來決定主體是否有權限進行相應的操作;即 控 制著用戶能訪問應用中的哪些功能。
- Realm:可以有 1 個或多個 Realm,可以認為是安全實體數據源,即用于獲取安全實 體 的;可以是 JDBC實現,也可以是內存實現等等;由用戶提供;所以一般在應用中都需 要 實現自己的 Realm。
- SessionManager:管理 Session 生命周期的組件;而 Shiro 并不僅僅可以用在 Web 環(huán)境,也可以用在如普通的JavaSE 環(huán)境。
- CacheManager:緩存控制器,來管理如用戶、角色、權限等的緩存的;因為這些數據 基本上很少改變,放到緩存中后可以提高訪問的性能。
- Cryptography:密碼模塊,Shiro 提高了一些常見的加密組件用于如密碼加密/解密。
2、基本使用
2.1、Shiro不依賴容器,直接創(chuàng)建maven工程即可
2.2、添加依賴
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
2.3、 INI 文件
Shiro 獲取權限相關信息可以通過數據庫獲取,也可以通過 ini 配置文件獲取
2.4、登錄認證
2.4.1、登錄認證概念
- 身份驗證:一般需要提供如身份ID等一些標識信息來表明登錄者的身份,如提供 email,用戶名/密碼來證明。
- 在shiro中,用戶需要提供principals(身份)和credentials(證明)給shiro,從 而應用能驗證用戶身份。
- principals:身份,即主體的標識屬性,可以是任何屬性,如用戶名、郵箱等,唯一即可。一個主體可以有多個principals,但只有一個Primary principals,一般是用戶名/ 郵箱/手機號。
- credentials:證明/憑證,即只有主體知道的安全值,如密碼/數字證書等。
- 最常見的principals和credentials組合就是用戶名/密碼。
2.4.2、登錄認證基本流程
- 收集用戶身份/憑證,即如用戶名/密碼。
- 調用 Subject.login 進行登錄,如果失敗將得到相應的 AuthenticationException 異常,根據異常提示用戶 錯誤信息;否則登錄成功。
- 創(chuàng)建自定義的 Realm 類,繼承org.apache.shiro.realm.AuthenticatingRealm類, 實現 doGetAuthenticationInfo() 方法。
2.5、登錄認證實例
2.5.1、創(chuàng)建測試類,獲取認證對象,進行登錄認證,如下:
public class ShiroRun {
public static void main(String[] args) {
//1初始化獲取SecurityManager
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//2獲取Subject對象
Subject subject = SecurityUtils.getSubject();
//3創(chuàng)建token對象,web應用用戶名密碼從頁面?zhèn)鬟f
AuthenticationToken token = new UsernamePasswordToken("zhangsan","123");
//4完成登錄
try {
subject.login(token);
System.out.println("登錄成功");
} catch (UnknownAccountException e){
e.printStackTrace();
System.out.println("用戶不存在");
} catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密碼錯誤");
}catch (Exception e) {
e.printStackTrace();
}
}
}
2.5.2、測試
- 登錄成功
-
用戶名不存在
-
密碼錯誤
2.6、身份認證流程
- 首先調用 Subject.login(token) 進行登錄,其會自動委托給 SecurityManager。
- SecurityManager 負責真正的身份驗證邏輯;它會委托給 Authenticator 進行身份 驗證。
- Authenticator 才是真正的身份驗證者,Shiro API 中核心的身份認證入口點,此 處可以自定義插入自己的實現。
- Authenticator 可能會委托給相應的 AuthenticationStrategy 進 行多 Realm 身份 驗證,默認ModularRealmAuthenticator 會調用 AuthenticationStrategy 進行多 Realm 身份驗證。
- Authenticator 會把相應的 token 傳入 Realm,從 Realm 獲取 身份驗證信息,如果沒有返回/拋出異常表示身份驗證失敗了。此處 可以配置多個Realm,將按照相應的順序 及策略進行訪問。
2.7、角色、授權
2.7.1、授權概念
- 授權,也叫訪問控制,即在應用中控制誰訪問哪些資源(如訪問頁面/編輯數據/頁面 操作等)。在授權中需了解的幾個關鍵對象:主體(Subject)、資源(Resource)、權 限(Permission)、角色(Role)。
- 主體(Subject):訪問應用的用戶,在 Shiro 中使用 Subject 代表該用戶。用戶只有授權后才允許訪問相應的資源。
- 資源(Resource):在應用中用戶可以訪問的 URL,比如訪問 JSP 頁面、查看/編輯某些數據、訪問某個業(yè)務方法、打印文本等等都是資源。用戶只要授權后才能訪問。
- 權限(Permission):安全策略中的原子授權單位,通過權限我們可以表示在應用中 用戶有沒有操作某個資源的權力。即權限表示在應用中用戶能不能訪問某個資源,如:訪問用戶列表頁面查看/新增/修改/刪除用戶數據(即很多時候都是CRUD(增查改刪)式權 限控制)等。權限代表了用戶有沒有操作某個資源的權利,即反映在某個資源上的操作允 不允許。
- Shiro 支持粗粒度權限(如用戶模塊的所有權限)和細粒度權限(操作某個用戶的權限, 即實例級別的)。
- 角色(Role):權限的集合,一般情況下會賦予用戶角色而不是權限,即這樣用戶可以擁有一組權限,賦予權限時比較方便。典型的如:項目經理、技術總監(jiān)、CTO、開發(fā)工 程師等都是角色,不同的角色擁有一組不同的權限。
2.7.2、授權方式
- 編程式:通過寫if/else 授權代碼塊完成
if (subject.hasRole("admin")){
//有權限
} else {
//無權限
}
- 注解式:通過在執(zhí)行的Java方法上放置相應的注解完成,沒有權限將拋出相 應的異常
@RequiresRoles("admin")
public void test(){
//有權限
}
- JSP/GSP 標簽:在JSP/GSP 頁面通過相應的標簽完成
<shiro:hasRole name="admin">
<!--有權限-->
</shiro:hasRole>
2.7.3、授權流程
- 首先調用Subject.isPermitted*/hasRole*接口,其會委托給SecurityManager,而SecurityManager接著會委托給 Authorizer。
- Authorizer是真正的授權者,如果調用如isPermitted(“user:view”),其首先會通過PermissionResolver把字符串轉換成相應的Permission實例。
- 在進行授權之前,其會調用相應的Realm獲取Subject相應的角色/權限用于匹配傳入的角色/權限。
- Authorizer會判斷Realm的角色/權限是否和傳入的匹配,如果有多個Realm,會委托給ModularRealmAuthorizer進行循環(huán)判斷,如果匹配如isPermitted*/hasRole* 會返回true,否則返回false表示授權失敗。
2.8、授權實例
2.8.1、獲取角色信息
-
給shiro.ini增加角色配置
-
給例子添加代碼,溝通過hasRole()判斷用戶是否有指定角色
//5.判斷角色
boolean role1 = subject.hasRole("role1");
System.out.println("是否擁有此角色:"+role1);
- 測試
2.8.2、判斷權限信息
- 給shiro.ini增加權限配置
- 給例子添加代碼,判斷用戶是否有指定權限
//6.判斷權限
boolean permitted = subject.isPermitted("user:insert111");
System.out.println("是否用有此權限:"+permitted);
//也可以用checkPermission方法,但沒有返回值,沒權限拋AuthenticationException
subject.checkPermission("user:select1111");
-
測試
2.9、Shiro 加密
實際系統(tǒng)開發(fā)中,一些敏感信息需要進行加密,比如說用戶的密碼。Shiro 內嵌很多常用的加密算法,比如 MD5 加密。Shiro 可以很簡單的使用信息加密。
使用Shiro進行密碼加密.
public class ShiroMD5 {
public static void main(String[] args) {
String password = "123456";
//使用md5加密
// toHex():轉換為它的HEX(十六進制)
Md5Hash md51 = new Md5Hash(password);
System.out.println("md5加密:"+md51.toHex());
//帶鹽的md5加密,鹽就是在密碼明文后拼接新字符串,然后再進行加密
Md5Hash md52 = new Md5Hash(password,"salt");
System.out.println("帶鹽的MD5加密:"+md52.toHex());
//為了保證安全,避免被破解還可以多次迭代加密,保證數據安全
Md5Hash md53 = new Md5Hash(password,"salt",3);
System.out.println("md5帶鹽的3次加密:"+md53.toHex());
//使用父類進行加密
SimpleHash simpleHash = new SimpleHash("MD5",password,"salt",3);
System.out.println("父類帶鹽的3次加密:"+simpleHash.toHex());
}
}
2.10、Shiro 自定義登錄認證
Shiro 默認的登錄認證是不帶加密的,如果想要實現加密認證需要自定義登錄認證,自定義 Realm。文章來源:http://www.zghlxwxcb.cn/news/detail-464332.html
- 自定義登錄認證
public class MyRealm extends AuthenticatingRealm {
//自定義登錄認證方法,shiro的login方法底層會調用該類的認證方法進行認證
//需要配置自定義的realm生效,在ini文件中配置,在Springboot中配置
//該方法只是獲取進行對比的信息,認證邏輯還是按照shiro底層認證邏輯完成
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.獲取身份信息
String principal = authenticationToken.getPrincipal().toString();
//2.獲取憑證信息
String password = new String((char[])authenticationToken.getCredentials());
System.out.println("認證用戶信息:"+principal + "----"+password);
//3.獲取數據庫中存儲的用戶信息
if (principal.equals("zhangsan")){
//3.1數據庫中存儲的加鹽3次迭代的密碼
String pwdInfo = "d1b129656359e35e95ebd56a63d7b9e0";
//4創(chuàng)建封裝校驗邏輯對象,封裝數據返回
AuthenticationInfo info = new SimpleAuthenticationInfo(
authenticationToken.getPrincipal(),
pwdInfo,
ByteSource.Util.bytes("salt"),
authenticationToken.getPrincipal().toString()
);
return info;
}
return null;
}
}
- 在shiro.ini中添加配置信息
[main]
md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
md5CredentialsMatcher.hashIterations=3
myrealm=com.shiro.MyRealm //自定義realm的路徑
myrealm.credentialsMatcher=$md5CredentialsMatcher
securityManager.realms=$myrealm
[users]
zhangsan=d1b129656359e35e95ebd56a63d7b9e0,role1,role2
lisi=456
[roles]
role1:insert,user:select
- 使用加密的密碼
- 運行測試
結束?。?!文章來源地址http://www.zghlxwxcb.cn/news/detail-464332.html
個性像白紙,一經污染,便永不能再如以前的潔白。——黑格爾
到了這里,關于shiro 安全(權限)框架的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!