更新時間:2020-08-14 來源:黑馬程序員 瀏覽量:
【1】Realm接口
所以,一般在真實的項目中,我們不會直接實現(xiàn)Realm接口,我們一般的情況就是直接繼承AuthorizingRealm,能夠繼承到認證與授權功能,它需要強制重寫兩個方法。
public class DefinitionRealm extends AuthorizingRealm { /** * @Description 認證 * @param authcToken token對象 * @return */ public abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) { return null; } /** * @Description 鑒權 * @param principals 令牌 * @return */ public abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){ return null; } }
【2】自定義Realm
【2.1】需求
1、自定義Realm,取得密碼用于比較。
【2.2】實現(xiàn)
【2.2.1】創(chuàng)建項目
shiro-day01-02realm
【2.2.2】定義SecurityService
SecurityService
package com.itheima.shiro.service; /** * @Description:權限服務接口 */ 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:權限服務層 */ 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 認證接口 * @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("賬戶不存在"); } //傳遞賬號和密碼 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 #聲明用戶賬號 #[users] #jay=123
【3】認證源碼跟蹤
(1)通過debug模式追蹤源碼subject.login(token)
發(fā)現(xiàn)。首先是進入Subject接口的默認實現(xiàn)類。果然,Subject將用戶的用戶名密碼委托給了securityManager去做。
(2)然后,securityManager說:“臥槽,認證器authenticator小弟,聽說你的大學學的專業(yè)就是認證呀,那么這個認證的任務就交給你咯”。遂將用戶的token委托給內(nèi)部認證組件authenticator去做。
(3)事實上,securityManager的內(nèi)部組件一個比一個懶。內(nèi)部認證組件authenticator說:“你們傳過來的token我需要拿去跟數(shù)據(jù)源Realm做對比,這樣吧,這個光榮的任務就交給Realm你去做吧”。Realm對象:“一群大懶蟲!”。
(4)Realm在接到內(nèi)部認證組件authenticator組件后很傷心,最后對電腦前的你說:“大兄弟,對不住了,你去實現(xiàn)一下唄”。從圖中的方法體中可以看到,當前對象是Realm類對象,即將調(diào)用的方法是doGetAuthenticationInfo(token)。而這個方法,就是你即將要重寫的方法。如果帳號密碼通過了,那么返回一個認證成功的info憑證。如果認證失敗,拋出一個異常就好了。你說:“什么?最終還是勞資來認證?”沒錯,就是苦逼的你去實現(xiàn)了,誰叫你是程序猿呢。所以,你不得不查詢一下數(shù)據(jù)庫,重寫doGetAuthenticationInfo方法,查出來正確的帳號密碼,返回一個正確的憑證info。
(5)好了,這個時候你自己編寫了一個類,繼承了AuthorizingRealm,并實現(xiàn)了上述doGetAuthenticationInfo方法。你在doGetAuthenticationInfo中編寫了查詢數(shù)據(jù)庫的代碼,并將數(shù)據(jù)庫中存放的用戶名與密碼封裝成了一個AuthenticationInfo對象返回??梢钥吹较聢D中,info這個對象是有值的,說明從數(shù)據(jù)庫中查詢出來了正確的帳號密碼。
(6)那么,接下來就很簡單了。把用戶輸入的帳號密碼與剛才你從數(shù)據(jù)庫中查出來的帳號密碼對比一下即可。token封裝著用戶的帳號密碼,AuthenticationInfo封裝著從數(shù)據(jù)庫中查詢出來的帳號密碼。再往下追蹤一下代碼,最終到了下圖中的核心區(qū)域。如果沒有報異常,說明本次登錄成功。
猜你喜歡: