Apache Shiro 使用手冊(cè)(二) Shiro 認(rèn)證
一、Shiro認(rèn)證過(guò)程
1、收集實(shí)體/憑據(jù)信息
//Example using most common scenario of username/password pair:
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//”Remember Me” built-in:
token.setRememberMe(true);
UsernamePasswordToken支持最常見(jiàn)的用戶(hù)名/密碼的認(rèn)證機(jī)制。同時(shí),由于它實(shí)現(xiàn)了RememberMeAuthenticationToken接口,我們可以通過(guò)令牌設(shè)置“記住我”的功能。
但是,“已記住”和“已認(rèn)證”是有區(qū)別的:
已記住的用戶(hù)僅僅是非匿名用戶(hù),你可以通過(guò)subject.getPrincipals()獲取用戶(hù)信息。但是它并非是完全認(rèn)證通過(guò)的用戶(hù),當(dāng)你訪(fǎng)問(wèn)需要認(rèn)證用戶(hù)的功能時(shí),你仍然需要重新提交認(rèn)證信息。
這一區(qū)別可以參考亞馬遜網(wǎng)站,網(wǎng)站會(huì)默認(rèn)記住登錄的用戶(hù),再次訪(fǎng)問(wèn)網(wǎng)站時(shí),對(duì)于非敏感的頁(yè)面功能,頁(yè)面上會(huì)顯示記住的用戶(hù)信息,但是當(dāng)你訪(fǎng)問(wèn)網(wǎng)站賬戶(hù)信息時(shí)仍然需要再次進(jìn)行登錄認(rèn)證。
2、提交實(shí)體/憑據(jù)信息
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
收集了實(shí)體/憑據(jù)信息之后,我們可以通過(guò)SecurityUtils工具類(lèi),獲取當(dāng)前的用戶(hù),然后通過(guò)調(diào)用login方法提交認(rèn)證。
3、認(rèn)證處理
try {
currentUser.login(token);
} catch ( UnknownAccountException uae ) { ...
} catch ( IncorrectCredentialsException ice ) { ...
} catch ( LockedAccountException lae ) { ...
} catch ( ExcessiveAttemptsException eae ) { ...
} ... catch your own ...
} catch ( AuthenticationException ae ) {
//unexpected error?
}
如果login方法執(zhí)行完畢且沒(méi)有拋出任何異常信息,那么便認(rèn)為用戶(hù)認(rèn)證通過(guò)。之后在應(yīng)用程序任意地方調(diào)用SecurityUtils.getSubject() 都可以獲取到當(dāng)前認(rèn)證通過(guò)的用戶(hù)實(shí)例,使用subject.isAuthenticated()判斷用戶(hù)是否已驗(yàn)證都將返回true.
相反,如果login方法執(zhí)行過(guò)程中拋出異常,那么將認(rèn)為認(rèn)證失敗。Shiro有著豐富的層次鮮明的異常類(lèi)來(lái)描述認(rèn)證失敗的原因,如代碼示例。
二、登出操作
登出操作可以通過(guò)調(diào)用subject.logout()來(lái)刪除你的登錄信息,如:
currentUser.logout(); //removes all identifying information and invalidates their session too.
當(dāng)執(zhí)行完登出操作后,Session信息將被清空,subject將被視作為匿名用戶(hù)。
三、認(rèn)證內(nèi)部處理機(jī)制
以上,是Shiro認(rèn)證在應(yīng)用程序中的處理過(guò)程,下面將詳細(xì)解說(shuō)Shiro認(rèn)證的內(nèi)部處理機(jī)制。
如上圖,我們通過(guò)Shiro架構(gòu)圖的認(rèn)證部分,來(lái)說(shuō)明Shiro認(rèn)證內(nèi)部的處理順序:
1、應(yīng)用程序構(gòu)建了一個(gè)終端用戶(hù)認(rèn)證信息的AuthenticationToken 實(shí)例后,調(diào)用Subject.login方法。
2、Sbuject的實(shí)例通常是DelegatingSubject類(lèi)(或子類(lèi))的實(shí)例對(duì)象,在認(rèn)證開(kāi)始時(shí),會(huì)委托應(yīng)用程序設(shè)置的securityManager實(shí)例調(diào)用securityManager.login(token)方法。
3、SecurityManager接受到token(令牌)信息后會(huì)委托內(nèi)置的Authenticator的實(shí)例(通常都是ModularRealmAuthenticator類(lèi)的實(shí)例)調(diào)用authenticator.authenticate(token). ModularRealmAuthenticator在認(rèn)證過(guò)程中會(huì)對(duì)設(shè)置的一個(gè)或多個(gè)Realm實(shí)例進(jìn)行適配,它實(shí)際上為Shiro提供了一個(gè)可拔插的認(rèn)證機(jī)制。
4、如果在應(yīng)用程序中配置了多個(gè)Realm,ModularRealmAuthenticator會(huì)根據(jù)配置的AuthenticationStrategy(認(rèn)證策略)來(lái)進(jìn)行多Realm的認(rèn)證過(guò)程。在Realm被調(diào)用后,AuthenticationStrategy將對(duì)每一個(gè)Realm的結(jié)果作出響應(yīng)。
注:如果應(yīng)用程序中僅配置了一個(gè)Realm,Realm將被直接調(diào)用而無(wú)需再配置認(rèn)證策略。
5、判斷每一個(gè)Realm是否支持提交的token,如果支持,Realm將調(diào)用getAuthenticationInfo(token); getAuthenticationInfo 方法就是實(shí)際認(rèn)證處理,我們通過(guò)覆蓋Realm的doGetAuthenticationInfo方法來(lái)編寫(xiě)我們自定義的認(rèn)證處理。
四、使用多個(gè)Realm的處理機(jī)制:
1、Authenticator
默認(rèn)實(shí)現(xiàn)是ModularRealmAuthenticator,它既支持單一Realm也支持多個(gè)Realm。如果僅配置了一個(gè)Realm,ModularRealmAuthenticator 會(huì)直接調(diào)用該Realm處理認(rèn)證信息,如果配置了多個(gè)Realm,它會(huì)根據(jù)認(rèn)證策略來(lái)適配Realm,找到合適的Realm執(zhí)行認(rèn)證信息。
自定義Authenticator的配置:
[main]
...
authenticator = com.foo.bar.CustomAuthenticator
securityManager.authenticator = $authenticator
2、AuthenticationStrategy(認(rèn)證策略)
當(dāng)應(yīng)用程序配置了多個(gè)Realm時(shí),ModularRealmAuthenticator將根據(jù)認(rèn)證策略來(lái)判斷認(rèn)證成功或是失敗。
例如,如果只有一個(gè)Realm驗(yàn)證成功,而其他Realm驗(yàn)證失敗,那么這次認(rèn)證是否成功呢?如果大多數(shù)的Realm驗(yàn)證成功了,認(rèn)證是否就認(rèn)為成功呢?或者,一個(gè)Realm驗(yàn)證成功后,是否還需要判斷其他Realm的結(jié)果?認(rèn)證策略就是根據(jù)應(yīng)用程序的需要對(duì)這些問(wèn)題作出決斷。
認(rèn)證策略是一個(gè)無(wú)狀態(tài)的組件,在認(rèn)證過(guò)程中會(huì)經(jīng)過(guò)4次的調(diào)用:
在所有Realm被調(diào)用之前
在調(diào)用Realm的getAuthenticationInfo 方法之前
在調(diào)用Realm的getAuthenticationInfo 方法之后
在所有Realm被調(diào)用之后
認(rèn)證策略的另外一項(xiàng)工作就是聚合所有Realm的結(jié)果信息封裝至一個(gè)AuthenticationInfo實(shí)例中,并將此信息返回,以此作為Subject的身份信息。
Shiro有3中認(rèn)證策略的具體實(shí)現(xiàn):
AtLeastOneSuccessfulStrategy | 只要有一個(gè)(或更多)的Realm驗(yàn)證成功,那么認(rèn)證將被視為成功 |
FirstSuccessfulStrategy | 第一個(gè)Realm驗(yàn)證成功,整體認(rèn)證將被視為成功,且后續(xù)Realm將被忽略 |
AllSuccessfulStrategy | 所有Realm成功,認(rèn)證才視為成功 |
ModularRealmAuthenticator 內(nèi)置的認(rèn)證策略默認(rèn)實(shí)現(xiàn)是AtLeastOneSuccessfulStrategy 方式,因?yàn)檫@種方式也是被廣泛使用的一種認(rèn)證策略。當(dāng)然,你也可以通過(guò)配置文件定義你需要的策略,如:
[main]
...
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
...
3、Realm的順序
由剛才提到的認(rèn)證策略,可以看到Realm在ModularRealmAuthenticator 里面的順序?qū)φJ(rèn)證是有影響的。
ModularRealmAuthenticator 會(huì)讀取配置在SecurityManager里的Realm。當(dāng)執(zhí)行認(rèn)證是,它會(huì)遍歷Realm集合,對(duì)所有支持提交的token的Realm調(diào)用getAuthenticationInfo 。
因此,如果Realm的順序?qū)δ闶褂玫恼J(rèn)證策略結(jié)果有影響,那么你應(yīng)該在配置文件中明確定義Realm的順序,如:
blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm
securityManager.realms = $fooRealm, $barRealm, $blahRealm
相關(guān)文章
Centos7之如何設(shè)置定時(shí)任務(wù)
這篇文章主要介紹了Centos7之如何設(shè)置定時(shí)任務(wù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06linux adsl 撥號(hào)自動(dòng)配置腳本的方法
本篇文章主要介紹了linux adsl 撥號(hào)自動(dòng)配置腳本的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07電腦意外關(guān)機(jī)后VMware中l(wèi)inux不能聯(lián)網(wǎng)問(wèn)題的解決方法
這篇文章主要為大家解決電腦意外關(guān)機(jī)后,再次開(kāi)機(jī)啟動(dòng)VMware時(shí)發(fā)現(xiàn)linux不能聯(lián)網(wǎng)的問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03詳解ubuntu20.04下CLion2020.1.3安裝配置ROS過(guò)程說(shuō)明
這篇文章主要介紹了ubuntu20.04下CLion2020.1.3安裝配置ROS過(guò)程說(shuō)明,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08Linux內(nèi)核設(shè)備驅(qū)動(dòng)地址映射筆記整理
今天小編就為大家分享一篇關(guān)于Linux內(nèi)核設(shè)備驅(qū)動(dòng)地址映射筆記整理,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12linux nand flash驅(qū)動(dòng)編寫(xiě)
這篇文章主要介紹了linux nand flash驅(qū)動(dòng)編寫(xiě),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04LAMP服務(wù)器性能優(yōu)化技巧之Apache服務(wù)器優(yōu)化
目前LAMP (Linux + Apache + MySQL + PHP) 近幾年來(lái)發(fā)展迅速,已經(jīng)成為Web 服務(wù)器的事實(shí)標(biāo)準(zhǔn)。本文我們將介紹基于LAMP組合的服務(wù)器的性能優(yōu)化技巧2012-02-02linux后臺(tái)執(zhí)行命令&和nohup的具體使用方法
這篇文章主要介紹了linux后臺(tái)執(zhí)行命令&和nohup的具體使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09