【1】Realm接口
所以,一般在真實(shí)的項(xiàng)目中,我們不會(huì)直接實(shí)現(xiàn)Realm接口,我們一般的情況就是直接繼承AuthorizingRealm,能夠繼承到認(rèn)證與授權(quán)功能,它需要強(qiáng)制重寫(xiě)兩個(gè)方法。
public class DefinitionRealm extends AuthorizingRealm {
/**
* @Description 認(rèn)證
* @param authcToken token對(duì)象
* @return
*/
public abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
return null;
}
/**
* @Description 鑒權(quán)
* @param principals 令牌
* @return
*/
public abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
return null;
}
}
【2】自定義Realm
【2.1】需求
1、自定義Realm,取得密碼用于比較。
【2.2】實(shí)現(xiàn)
【2.2.1】創(chuàng)建項(xiàng)目
shiro-day01-02realm
【2.2.2】定義SecurityService
SecurityService
package com.itheima.shiro.service;
/**
* @Description:權(quán)限服務(wù)接口
*/
public interface SecurityService {
/**
* @Description 查找密碼按用戶登錄名
* @param loginName 登錄名稱
* @return
*/
String findPasswordByLoginName(String loginName);
}
SecurityServiceImpl
package com.itheima.shiro.service.impl;
import com.itheima.shiro.service.SecurityService;
/**
* @Description:權(quán)限服務(wù)層
*/
public class SecurityServiceImpl implements SecurityService {
@Override
public String findPasswordByLoginName(String loginName) {
return "123";
}
}
【2.2.3】定義DefinitionRealm
package com.itheima.shiro.realm;
import com.itheima.shiro.service.SecurityService;
import com.itheima.shiro.service.impl.SecurityServiceImpl;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* @Description:聲明自定義realm
*/
public class DefinitionRealm extends AuthorizingRealm {
/**
* @Description 認(rèn)證接口
* @param token 傳遞登錄token
* @return
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//從AuthenticationToken中獲得登錄名稱
String loginName = (String) token.getPrincipal();
SecurityService securityService = new SecurityServiceImpl();
String password = securityService.findPasswordByLoginName(loginName);
if ("".equals(password)||password==null){
throw new UnknownAccountException("賬戶不存在");
}
//傳遞賬號(hào)和密碼
return new SimpleAuthenticationInfo(loginName,password,getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
}
【2.2.4】編輯shiro.ini
#聲明自定義的realm,且為安全管理器指定realms
[main]
definitionRealm=com.itheima.shiro.realm.DefinitionRealm
securityManager.realms=$definitionRealm
#聲明用戶賬號(hào)
#[users]
#jay=123
【3】認(rèn)證源碼跟蹤
(1)通過(guò)debug模式追蹤源碼subject.login(token) 發(fā)現(xiàn)。首先是進(jìn)入Subject接口的默認(rèn)實(shí)現(xiàn)類。果然,Subject將用戶的用戶名密碼委托給了securityManager去做。
(2)然后,securityManager說(shuō):“臥槽,認(rèn)證器authenticator小弟,聽(tīng)說(shuō)你的大學(xué)學(xué)的專業(yè)就是認(rèn)證呀,那么這個(gè)認(rèn)證的任務(wù)就交給你咯”。遂將用戶的token委托給內(nèi)部認(rèn)證組件authenticator去做。
(3)事實(shí)上,securityManager的內(nèi)部組件一個(gè)比一個(gè)懶。內(nèi)部認(rèn)證組件authenticator說(shuō):“你們傳過(guò)來(lái)的token我需要拿去跟數(shù)據(jù)源Realm做對(duì)比,這樣吧,這個(gè)光榮的任務(wù)就交給Realm你去做吧”。Realm對(duì)象:“一群大懶蟲(chóng)!”。
(4)Realm在接到內(nèi)部認(rèn)證組件authenticator組件后很傷心,最后對(duì)電腦前的你說(shuō):“大兄弟,對(duì)不住了,你去實(shí)現(xiàn)一下唄”。從圖中的方法體中可以看到,當(dāng)前對(duì)象是Realm類對(duì)象,即將調(diào)用的方法是doGetAuthenticationInfo(token)。而這個(gè)方法,就是你即將要重寫(xiě)的方法。如果帳號(hào)密碼通過(guò)了,那么返回一個(gè)認(rèn)證成功的info憑證。如果認(rèn)證失敗,拋出一個(gè)異常就好了。你說(shuō):“什么?最終還是勞資來(lái)認(rèn)證?”沒(méi)錯(cuò),就是苦逼的你去實(shí)現(xiàn)了,誰(shuí)叫你是程序猿呢。所以,你不得不查詢一下數(shù)據(jù)庫(kù),重寫(xiě)doGetAuthenticationInfo方法,查出來(lái)正確的帳號(hào)密碼,返回一個(gè)正確的憑證info。
(5)好了,這個(gè)時(shí)候你自己編寫(xiě)了一個(gè)類,繼承了AuthorizingRealm,并實(shí)現(xiàn)了上述doGetAuthenticationInfo方法。你在doGetAuthenticationInfo中編寫(xiě)了查詢數(shù)據(jù)庫(kù)的代碼,并將數(shù)據(jù)庫(kù)中存放的用戶名與密碼封裝成了一個(gè)AuthenticationInfo對(duì)象返回。可以看到下圖中,info這個(gè)對(duì)象是有值的,說(shuō)明從數(shù)據(jù)庫(kù)中查詢出來(lái)了正確的帳號(hào)密碼。
(6)那么,接下來(lái)就很簡(jiǎn)單了。把用戶輸入的帳號(hào)密碼與剛才你從數(shù)據(jù)庫(kù)中查出來(lái)的帳號(hào)密碼對(duì)比一下即可。token封裝著用戶的帳號(hào)密碼,AuthenticationInfo封裝著從數(shù)據(jù)庫(kù)中查詢出來(lái)的帳號(hào)密碼。再往下追蹤一下代碼,最終到了下圖中的核心區(qū)域。如果沒(méi)有報(bào)異常,說(shuō)明本次登錄成功。
猜你喜歡:
Java arraylist使用教程
手動(dòng)實(shí)現(xiàn)IOC容器:SpringIOC底層實(shí)現(xiàn)原理
什么是Shiro?Shiro有什么特點(diǎn)?
系統(tǒng)身份認(rèn)證流程
Java高級(jí)軟件工程師培訓(xùn)課程