寫在前面:
小夥伴兒們,大家好!這次讓我們一起來學習Shiro權限框架吧!
思維導圖:
1,初識Shiro
1.1,簡介;
Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼和會話管理。使用Shiro的易於理解的API,您可以快速、輕鬆地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。
1.2,入門配置;
創建Maven工程命名爲Shiro,結構圖如下;
直接引入依賴:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.5.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>2.0.0-alpha1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
log4j.properties配置文件:
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
# General Apache libraries
log4j.logger.org.apache=WARN
# Spring
log4j.logger.org.springframework=WARN
# Default Shiro logging
log4j.logger.org.apache.shiro=TRACE
# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
shiro.ini文件(放在resources目錄下),以鍵值對地形式存放:
[users]
java=123456
jack=123
1.3,程序文件;
我們新建一個HelloWorld類:
package com.java;
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 org.apache.shiro.util.Factory;
public class HelloWorld {
public static void main(String[] args) {
// 讀取配置文件,初始化SecurityManager工廠
Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
// 獲取securityManager實例
SecurityManager securityManager=factory.getInstance();
// 把securityManager實例綁定到SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
// 得到當前執行的用戶
Subject currentUser=SecurityUtils.getSubject();
// 創建token令牌,用戶名/密碼
UsernamePasswordToken token=new UsernamePasswordToken("java", "123456");
try{
// 身份認證
currentUser.login(token);
System.out.println("身份認證成功!");
}catch(AuthenticationException e){
e.printStackTrace();
System.out.println("身份認證失敗!");
}
// 退出
currentUser.logout();
}
}
首先通過 new IniSecurityManagerFa ctory 並指定一個 ini 配置文件來創建一個 SecurityManager 工廠;
接着獲取 SecurityManager 並綁定到 SecurityUtils,這是一個全局設置,設置一次即可;
通過 SecurityUtils 得到 Subject,其會自動綁定到當前線程;如果在 web 環境在請求結束時需要解除綁定;然後獲取身份驗證的 Token,如用戶名 / 密碼;
調用 subject.login 方法進行登錄,其會自動委託給 SecurityManager.lo gin 方法進行登錄;
如果身份驗證失敗請捕獲 Authenticat ionException 或其子類,常見的如:DisabledAccountException(禁用的帳號)、LockedAccountException(鎖定的帳號)、UnknownAccountExceptio n(錯誤的帳號)、ExcessiveAttempts Exception(登錄失敗次數過多)、In correctCredentialsException (錯誤的憑證)、ExpiredCredentialsException (過期的憑證)等,具體請查看其繼承關係;對於頁面的錯誤消息展示,最好使用如 “用戶名 / 密碼錯誤” 而不是 “用戶名錯誤”/“密碼錯誤”,防止一些惡意用戶非法掃描帳號庫;
最後可以調用 subject.logout 退出,其會自動委託給 SecurityManager.logout 方法退出。
運行:
從如上代碼可總結出身份驗證的步驟:
收集用戶身份 / 憑證,即如用戶名 / 密碼;
調用 Subject.login 進行登錄,如果失敗將得到相應的 AuthenticationException 異常,根據異常提示用戶錯誤信息;否則登錄成功;
最後調用 Subject.logout 進行退出操作。
2,Shiro身份認證;
2.1,Subject認證主體;
在 shiro 中,用戶需要提供 principals (身份)和 credentials(證明)給 shiro,從而應用能驗證用戶身份:
principals:身份,即主體的標識屬性,可以是任何東西,如用戶名、郵箱等,唯一即可。一個主體可以有多個 principals ,但只有一個 Primary principals,一般是用戶名 / 密碼 / 手機號。
credentials:證明 / 憑證,即只有主體知道的安全值,如密碼 / 數字證書等。最常見的 principals 和 credentials 組合就是用戶名 / 密碼了。接下來先進行一個基本的身份認證。另外兩個相關的概念是之前提到的 Subject 及 Realm,分別是主體及驗證主體的數據源。
2.2,身份認證流程;
流程如下:
首先調用 Subject.login(token) 進行登錄,其會自動委託給 Security Manager ,調用之前必須通過 SecurityUtils.set SecurityManager() 設置;
SecurityManager 負責真正的身份驗證邏輯;它會委託給 Authenticator 進行身份驗證;
Authenticator 纔是真正的身份驗證者,Shiro API 中核心的身份認證入口點,此處可以自定義插入自己的實現;
Authenticator 可能會委託給相應的 AuthenticationStrategy 進行多 Realm 身份驗證,默認 ModularRealmAuthen ticator 會調用 AuthenticationStrategy 進行多 Realm 身份驗證;
Authenticator 會把相應的 token 傳入 Realm,從 Realm 獲取身份驗證信息,如果沒有返回 / 拋出異常表示身份驗證失敗了。此處可以配置多個 Realm,將按照相應的順序及策略進行訪問。
2.3,Realm;
Realm:域,Shiro 從從 Realm 獲取安全數據(如用戶、角色、權限),就是說 SecurityManager 要驗證用戶身份,那麼它需要從 Realm 獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從 Realm 得到用戶相應的角色 / 權限進行驗證用戶是否能進行操作;可以把 Realm 看成 DataSource,即安全數據源。如我們之前的 ini 配置方式將使用 org.apache.shiro .realm.text.IniRealm。
realm種類很多,例如常見的 jdbc realm,jndi realm,text realm,我們這裏就瞭解一下jdbc realm,其他的不做敘述;
首先先建立數據庫db_shiro,然後添加表users(表名稱不可改),添加一條數據;
配置文件jdbc_realm.ini,這與上文的shiro.ini是一樣的;
[main] jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm dataSource=com.alibaba.druid.pool.DruidDataSource dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://localhost:3306/db_shiro dataSource.username=root dataSource.password=123456 jdbcRealm.dataSource=$dataSource securityManager.realms=$jdbcRealm
導入依賴
<!-- mysql 數據庫及 druid 連接池--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.25</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>0.2.23</version> </dependency>
測試程序(把路徑更改一下即可)
package com.java; 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 org.apache.shiro.util.Factory; public class JdbcRealmTest { public static void main(String[] args) { // 讀取配置文件,初始化SecurityManager工廠 Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:jdbc_realm.ini"); // 獲取securityManager實例 SecurityManager securityManager=factory.getInstance(); // 把securityManager實例綁定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到當前執行的用戶 Subject currentUser=SecurityUtils.getSubject(); // 創建token令牌,用戶名/密碼 UsernamePasswordToken token=new UsernamePasswordToken("java", "123"); try{ // 身份認證 currentUser.login(token); System.out.println("身份認證成功!"); }catch(AuthenticationException e){ e.printStackTrace(); System.out.println("身份認證失敗!"); } // 退出 currentUser.logout(); } }
運行結果
好了,今天就先分享到這裏了,下期繼續給大家帶來Shiro相關方面的學習!更多幹貨、優質文章,歡迎關注我的原創技術公衆號~