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-04
Springboot Mybatis Plus自動生成工具類詳解代碼
mybatis-plus 是一個 Mybatis 的增強工具,在 Mybatis 的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生,這篇文章帶你使用Springboot Mybatis Plus自動生成工具類2021-11-11
解決SpringBoot整合MybatisPlus分模塊管理遇到的bug
這篇文章主要介紹了解決SpringBoot整合MybatisPlus分模塊管理遇到的bug,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
jsp、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

