Spring Security認證系統(tǒng)淺析

Spring Security認證系統(tǒng)淺析-龍果學(xué)院 Spring Security認證系統(tǒng)淺析

標簽:安全發(fā)布于 2017-05-26 12:42:47

Spring Security是個安全框架眾所周知菊卷,同時也提供了一整套基于Web的認證機制和安全服務(wù)速勇,當然如果你要通過其他協(xié)議的來實現(xiàn)安全服務(wù)垢油,你也可以使用SpringSecurity來幫助你其障。

今天主要是講解基于web端的安全認證機制堰乔,其他的留著以后有空再整理成博文伴找。

首先SpringSecurity Web是基于它所提供的一整套Filter鏈來實現(xiàn)的锰镀,我們來看下它所提供的有哪些Filter:

在列表中可以看到斟赚,這些Filter鏈是有序的着降,而且自身所提供的Filter是無法更改順序的,so what拗军?任洞??當然发侵,你都能任意更改順序了交掏,那我怎么能保證在不同的filter中拿到正確的數(shù)據(jù)呢,是吧刃鳄?這些filter是SpringSecurity在啟動時會默認注入到容器中的盅弛,你可以根據(jù)自身業(yè)務(wù)的需要在這些filter的before或after插入自己設(shè)計的filter。

那每一個Filter具體是做了什么工作,大家自行去查閱熊尉,這不是今天講的重點罐柳,今天著重講基于web的認證機制。

先來看看SpringSecurity中認證時的幾個關(guān)鍵類:

org.springframework.security.web.context.SecurityContextRepository

org.springframework.security.web.context.SecurityContextPersistenceFilter

org.springframework.security.core.context.SecurityContextHolder

org.springframework.security.core.context.SecurityContextHolderStrategy

org.springframework.security.core.Authentication

首先來看下作為用戶在login時的交互圖狰住,這個圖確實太大了张吉,已經(jīng)盡量縮小了,但還是很大催植。

從圖中我們可以看到肮蛹,用戶在請求服務(wù)時,首先會經(jīng)過圖中的SecurityContextPersistenceFilter(其實這個類在Filter鏈中是第二個被處理的)创南,這個類是干嘛的呢伦忠,主要就是用于設(shè)置SecurityContext到SecurityContextHolder中,具體的我們通過圖和源碼一點點分析

首先看看SecurityContextPersistenceFilter.class

Java代碼

publicSecurityContextPersistenceFilter()?{

this(newHttpSessionSecurityContextRepository());

}

publicSecurityContextPersistenceFilter(SecurityContextRepository?repo)?{

this.repo?=?repo;

}

我們可以看到這個類的構(gòu)造方法是需要設(shè)置SecurityContextRepository的稿辙,默認會設(shè)置為HttpSessionSecurityContextRepository.class昆码,這個東西是拿來干嘛的?是用于設(shè)置SecurityContext的存儲機制的邻储,這個類對于你每次使用SecurityContextHolder在getContext時是否能拿到正確的context起到了關(guān)鍵性的作用赋咽。可以看到默認使用HttpSession來實現(xiàn)SecutiryContext的存儲吨娜。

接下來我們看看doFilter中干了些什么事:

Java代碼

HttpRequestResponseHolder?holder?=newHttpRequestResponseHolder(request,response);

//?這里可以看到從repo中取得SecurityContext脓匿,默認是從HttpSession里獲取

SecurityContext?contextBeforeChainExecution?=?repo.loadContext(holder);

try{

//?同時在這里將創(chuàng)建好的SecurityContext設(shè)置到SecurityContextHolder中????????????SecurityContextHolder.setContext(contextBeforeChainExecution);

chain.doFilter(holder.getRequest(),?holder.getResponse());

}

再來看一下repo.loadCotext的實現(xiàn)。

Java代碼

//?先從Session里去讀取是否存在SecurityContext

SecurityContext?context?=?readSecurityContextFromSession(httpSession);

//?如果不存在將創(chuàng)建一個空的SecurityContext

if(context?==null)?{

context?=?generateNewContext();

}

returncontext;

protectedSecurityContext?generateNewContext()?{

returnSecurityContextHolder.createEmptyContext();

}

privateSecurityContext?readSecurityContextFromSession(HttpSession?httpSession)?{

Object?contextFromSession?=?httpSession.getAttribute(springSecurityContextKey);

}

在這里可以看到如果Session是一個新的話宦赠,這里的ScurityContext會從SecurityContextHolder中去創(chuàng)建陪毡,在SecurityContextHolder中可以看到默認會通過ThreadLocalSecurityContextHolderStrategy創(chuàng)建一個基于ThreadLocal存儲線程安全的SecurityContext,那當前線程中所拿到的SecurityContext均是同一個實例勾扭。

現(xiàn)在知道了SecurityContext是如何創(chuàng)建了之后毡琉,再回頭來看SecurityContextPersistenceFilter中的doFilter實現(xiàn)

Java代碼

try{

//?在這里將創(chuàng)建好的SecurityContext設(shè)置到SecurityContextHolder中

SecurityContextHolder.setContext(contextBeforeChainExecution);

chain.doFilter(holder.getRequest(),?holder.getResponse());

}

現(xiàn)在已經(jīng)在chain.doFilter()之前已經(jīng)完成了對SecurityContext的設(shè)置,接下來過濾器鏈繼續(xù)執(zhí)行妙色,如果你在配置SecurityConfig中使用了UsernamePasswordAuthenticationFilter.class來實現(xiàn)對用戶的認證桅滋,那我們將會進入到UsernamePasswordAuthenticationFilter的doFilter來實現(xiàn)認證

Java代碼

Authentication?authResult;

try{

authResult?=?attemptAuthentication(request,?response);

if(authResult?==null)?{

//?return?immediately?as?subclass?has?indicated?that?it?hasn't?completed

//?authentication

return;

}

sessionStrategy.onAuthentication(authResult,?request,?response);

}

successfulAuthentication(request,?response,?chain,?authResult);

protectedvoidsuccessfulAuthentication(HttpServletRequest?request,

HttpServletResponse?response,?FilterChain?chain,?Authentication?authResult)

throwsIOException,?ServletException?{

if(logger.isDebugEnabled())?{

logger.debug("Authentication?success.?Updating?SecurityContextHolder?to?contain:?"

+?authResult);

}

SecurityContextHolder.getContext().setAuthentication(authResult);

rememberMeServices.loginSuccess(request,?response,?authResult);

//?Fire?event

if(this.eventPublisher?!=null)?{

eventPublisher.publishEvent(newInteractiveAuthenticationSuccessEvent(

authResult,this.getClass()));

}

successHandler.onAuthenticationSuccess(request,?response,?authResult);

}

Usernamepasswordauthenticationfilter代碼

public?Authentication?attemptAuthentication(HttpServletRequest?request,

HttpServletResponse?response)?throws?AuthenticationException?{

if?(postOnly?&&?!request.getMethod().equals("POST"))?{

throw?new?AuthenticationServiceException(

"Authentication?method?not?supported:?"+?request.getMethod());

}

String?username?=?obtainUsername(request);

String?password?=?obtainPassword(request);

if?(username?==?null)?{

username?="";

}

if?(password?==?null)?{

password?="";

}

username?=?username.trim();

UsernamePasswordAuthenticationToken?authRequest?=?new?UsernamePasswordAuthenticationToken(

username,?password);

//?Allow?subclasses?to?set?the"details"property

setDetails(request,?authRequest);

return?this.getAuthenticationManager().authenticate(authRequest);

}

一旦attemptAuthentication認證通過之后,可以在successfulAuthentication方法中可以看到調(diào)用了SecurityContextHolder.getContext().setAuthentication(authResult)來完成對用戶的認證燎斩,到這里已經(jīng)完成了基于SpringSecurity所提供的一套web完整的認證過程虱歪。

在這里就不對UsernamePasswordAuthenticationFilter里的認證機制做詳細的闡述了,大家有興趣的話自己去翻源碼查看吧栅表。還是比較簡單里笋鄙,里面設(shè)計到了AuthenticationManager、AuthenticationProvider怪瓶、UserDetailsService等相關(guān)的類萧落。

如果你使用的restful接口來實現(xiàn)認證的話践美,你也可以在驗證之后構(gòu)造一個Authentication實例,再通過SecurityContextHolder.getContext().setAuthentication( authentication )來實現(xiàn)對SpringSecurity的認證找岖。

原文請參考:Spring Security認證系統(tǒng)淺析-龍果學(xué)院? http://www.roncoo.com/article/detail/128454

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陨倡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子许布,更是在濱河造成了極大的恐慌兴革,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜜唾,死亡現(xiàn)場離奇詭異杂曲,居然都是意外死亡,警方通過查閱死者的電腦和手機袁余,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門擎勘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颖榜,你說我怎么就攤上這事棚饵。” “怎么了掩完?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵噪漾,是天一觀的道長。 經(jīng)常有香客問我藤为,道長怪与,這世上最難降的妖魔是什么夺刑? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任缅疟,我火速辦了婚禮,結(jié)果婚禮上遍愿,老公的妹妹穿的比我還像新娘存淫。我一直安慰自己,他們只是感情好沼填,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布桅咆。 她就那樣靜靜地躺著,像睡著了一般坞笙。 火紅的嫁衣襯著肌膚如雪岩饼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天薛夜,我揣著相機與錄音籍茧,去河邊找鬼。 笑死梯澜,一個胖子當著我的面吹牛寞冯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吮龄,長吁一口氣:“原來是場噩夢啊……” “哼俭茧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起漓帚,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤母债,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后尝抖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體场斑,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年牵署,在試婚紗的時候發(fā)現(xiàn)自己被綠了漏隐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡奴迅,死狀恐怖青责,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情取具,我是刑警寧澤脖隶,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站暇检,受9級特大地震影響产阱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜块仆,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一奸柬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鳖枕,春花似錦闰集、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至头滔,卻和暖如春怖亭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坤检。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工兴猩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缀蹄。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓峭跳,卻偏偏與公主長得像膘婶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛀醉,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容