Java的Shiro框架認(rèn)證流程詳解
1、Shiro框架介紹
- Shiro 是一個功能強大和易于使用的安全框架,為開發(fā)人員提供一個直觀而全面的解決方案的認(rèn)證,授權(quán),加密,會話管理四大功能!
- Subject:主體,subject記錄了當(dāng)前操作用戶,將當(dāng)前登錄訪問的用戶信息存在其中。
- Authenticator:身份認(rèn)證/登錄,驗證用戶賬號密碼是否正確。
- Authorizer:授權(quán),根據(jù)不同的用戶發(fā)放不同的權(quán)限。
- SessionManager:會話管理,它不依賴web容器的session,因此Shiro也可以使用在非web應(yīng)用上獨立使用
- Realm:領(lǐng)域范圍,securityManager進(jìn)行安全認(rèn)證需要通過Realm獲取數(shù)據(jù),然后與Subject中的數(shù)據(jù)進(jìn)行認(rèn)證授權(quán)!
- Cryptography:加密功能,將隱私數(shù)據(jù)進(jìn)行加密。
- SessionDAO:會話dao,是對session會話操作的一套接口,可以通過jdbc將會話數(shù)據(jù)存儲到數(shù)據(jù)庫。
- CacheManager:緩存管理,Shiro提供的緩存機制;為了提高效率。
2、入門案例
2.1、項目依賴
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.1</version> </dependency>
2.2、模擬數(shù)據(jù)
- resource/shiro.ini文件
- 一定是ini配置文件,并且使用鍵值對的形式
[users] zhangsan=123 admin=123456 splay=123456
2.3、案例
- 可以看到Shiro最核心的東西是SecurityManager安全管理器
- 然后初始化ini中的數(shù)據(jù)給Realm、Realm的數(shù)據(jù)正常是從數(shù)據(jù)庫中獲取的。
- 將SecurityManager安全管理器注入到SecurityUtil全局工具類中
- 最后創(chuàng)建令牌模擬用戶登錄進(jìn)行校驗!
- 當(dāng)用戶名不正確時拋出UnknownAccountException異常、密碼不對時拋出IncorrectCredentialsException異常!
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.subject.Subject; public class Application { public static void main(String[] args) { // 1. 創(chuàng)建安全管理器對象 DefaultSecurityManager securityManager = new DefaultSecurityManager(); // 2. 給安全管理器對象設(shè)置realm(模擬數(shù)據(jù)庫中的數(shù)據(jù)) securityManager.setRealm(new IniRealm("classpath:shiro.ini")); // 3. SecurityUtil設(shè)置全局的安全管理器 SecurityUtils.setSecurityManager(securityManager); // 4. 關(guān)鍵對象Subject主體對象 Subject subject = SecurityUtils.getSubject(); // 5. 模擬登錄(用戶名、密碼) UsernamePasswordToken user = new UsernamePasswordToken("splay", "123456"); try{ System.out.println("認(rèn)證狀態(tài): " + subject.isAuthenticated()); //登錄校驗 subject.login(user); System.out.println("認(rèn)證狀態(tài): " + subject.isAuthenticated()); } catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("認(rèn)證失敗: 用戶名密碼錯誤!"); } catch (UnknownAccountException e){ e.printStackTrace(); System.out.println("認(rèn)證失敗: 用戶名錯誤!"); } } }
3、源碼解析
- Shiro對整個登錄用戶的認(rèn)證分為兩個步驟:先校驗用戶名、其次校驗密碼;
- 主要涉及三個類:AuthenticatingRealm、AuthorizingRealm、SimpleAccountRealm
3.1、用戶名校驗
- 這里只校驗賬戶名是否被鎖定、證書是否過期這兩項。
- 并且這里的account返回為空是可以的。
public class SimpleAccountRealm extends AuthorizingRealm { protected SimpleAccount getUser(String username) { USERS_LOCK.readLock().lock(); //ReentrantReadWriteLock可重入讀寫鎖 try { return this.users.get(username); } finally { USERS_LOCK.readLock().unlock(); } } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { UsernamePasswordToken upToken = (UsernamePasswordToken) token; SimpleAccount account = getUser(upToken.getUsername()); if (account != null) { if (account.isLocked()) { //賬戶被鎖定 throw new LockedAccountException("Account [" + account + "] is locked."); } if (account.isCredentialsExpired()) { //憑證過期 String msg = "The credentials for account [" + account + "] are expired"; throw new ExpiredCredentialsException(msg); } } return account; } }
3.2、密碼校驗
當(dāng)用戶校驗返回值不為空時說明賬戶存在、沒有被鎖定、證書沒有過期時進(jìn)行密碼校驗。
public abstract class AuthenticatingRealm extends CachingRealm implements Initializable { public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); //校驗賬戶 log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) { //操作緩存 cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { assertCredentialsMatch(token, info); //見下方 } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; } protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException { CredentialsMatcher cm = getCredentialsMatcher(); if (cm != null) { if (!cm.doCredentialsMatch(token, info)) { // 密碼錯誤異常 String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials."; throw new IncorrectCredentialsException(msg); } } else { throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " + "credentials during authentication. If you do not wish for credentials to be examined, you " + "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance."); } } }
3.3、賬戶不存在異常
這里調(diào)用3.2中的方法、3.2中的調(diào)用3.1;實則Shiro封裝了很多層這里只是最重要的代碼。
public class ModularRealmAuthenticator extends AbstractAuthenticator { protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { if (!realm.supports(token)) { String msg = "Realm [" + realm + "] does not support authentication token [" + token + "]. Please ensure that the appropriate Realm implementation is " + "configured correctly or that the realm accepts AuthenticationTokens of this type."; throw new UnsupportedTokenException(msg); } AuthenticationInfo info = realm.getAuthenticationInfo(token); if (info == null) { String msg = "Realm [" + realm + "] was unable to find account data for the " + "submitted AuthenticationToken [" + token + "]."; throw new UnknownAccountException(msg); //賬戶不存在 } return info; } }
到此這篇關(guān)于Java的Shiro框架認(rèn)證流程詳解的文章就介紹到這了,更多相關(guān)Shiro框架認(rèn)證流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java連接mongoDB并進(jìn)行增刪改查操作實例詳解
這篇文章主要介紹了java連接mongoDB并進(jìn)行增刪改查操作,結(jié)合實例形式詳細(xì)分析了java環(huán)境下MongoDB擴展包的下載、安裝及操作MongoDB連接、增刪改查等相關(guān)操作技巧,需要的朋友可以參考下2019-04-04Springboot Mybatis Plus自動生成工具類詳解代碼
mybatis-plus 是一個 Mybatis 的增強工具,在 Mybatis 的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生,這篇文章帶你使用Springboot Mybatis Plus自動生成工具類2021-11-11解決SpringBoot整合MybatisPlus分模塊管理遇到的bug
這篇文章主要介紹了解決SpringBoot整合MybatisPlus分模塊管理遇到的bug,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07jsp、servlet前后端交互對數(shù)據(jù)處理及展示的簡單實現(xiàn)
Servlet和JSP是Java Web開發(fā)中的兩個重要概念,在Servlet和JSP中前后端交互可以通過一些方式來實現(xiàn),這篇文章主要給大家介紹了關(guān)于jsp、servlet前后端交互對數(shù)據(jù)處理及展示的簡單實現(xiàn),需要的朋友可以參考下2023-12-12