springsecurity的工作原理
結(jié)構(gòu)總覽
Spring Security所解決的問題就是安全訪問控制,
而安全訪問控制功能其實(shí)就是對(duì)所有進(jìn)入系統(tǒng)的請求進(jìn)行攔截,校驗(yàn)每個(gè)請求是否能夠訪問它所期望的資源。
根據(jù)前邊知識(shí)的學(xué)習(xí),可以通過Filter或AOP等技術(shù)來實(shí)現(xiàn),
Spring Security對(duì)Web資源的保護(hù)是靠Filter實(shí)現(xiàn)的,所以從這個(gè)Filter來入手,逐步深入Spring Security原理。
當(dāng)初始化Spring Security時(shí),會(huì)創(chuàng)建一個(gè)名為SpringSecurityFilterChain 的Servlet過濾器,
類型為org.springframework.security.web.FilterChainProxy,它實(shí)現(xiàn)了javax.servlet.Filter,
因此外部的請求會(huì)經(jīng)過此類,下圖是Spring Security過濾器鏈結(jié)構(gòu)圖:
FilterChainProxy是一個(gè)代理,
真正起作用的是FilterChainProxy中SecurityFilterChain所包含的各個(gè)Filter,
同時(shí)這些Filter作為Bean被Spring管理,它們是Spring Security核心,各有各的職責(zé),
但他們并不直接處理用戶的認(rèn)證,也不直接處理用戶的授權(quán),
而是把它們交給了認(rèn)證管理器(AuthenticationManager)和決策管理器(AccessDecisionManager)進(jìn)行處理,
下圖是FilterChainProxy相關(guān)類的UML圖示。
spring Security功能的實(shí)現(xiàn)主要是由一系列過濾器鏈相互配合完成。
下面介紹過濾器鏈中主要的幾個(gè)過濾器及其作用:
SecurityContextPersistenceFilter 這個(gè)Filter是整個(gè)攔截過程的入口和出口(也就是第一個(gè)和最后一個(gè)攔截器),
???????????????????????????????????????????????????????? 會(huì)在請求開始時(shí)從配置好的 SecurityContextRepository 中獲取 SecurityContext,
?????????????????????????????????????????????????????? ? 然后把它設(shè)置給SecurityContextHolder。
???????????????????????????????????????????????????????? 在請求完成后將 SecurityContextHolder 持有的 SecurityContext 再保存到配置好的 SecurityContextRepository,
???????????????????????????????????????????????????????? 同時(shí)清除 securityContextHolder 所持有的 SecurityContext;
UsernamePasswordAuthenticationFilter 用于處理來自表單提交的認(rèn)證。該表單必須提供對(duì)應(yīng)的用戶名和密碼,
??????????????????????????????????????????????????????????????????? 其內(nèi)部還有登錄成功或失敗后進(jìn)行處理的 AuthenticationSuccessHandler 和 AuthenticationFailureHandler,這些都可以根據(jù)需求做相關(guān)改變;
FilterSecurityInterceptor? 是用于保護(hù)web資源的,使用AccessDecisionManager對(duì)當(dāng)前用戶進(jìn)行授權(quán)訪問
ExceptionTranslationFilter ? 能夠捕獲來自 FilterChain 所有的異常,并進(jìn)行處理。但是它只會(huì)處理兩類異常:
??????????????????????????????????????????????? AuthenticationException 和 AccessDeniedException,其它的異常它會(huì)繼續(xù)拋出。
認(rèn)證流程
AuthenticationProvider
通過前面的Spring Security認(rèn)證流程得知,認(rèn)證管理器(AuthenticationManager)委托AuthenticationProvider完成認(rèn)證工作。
AuthenticationProvider是一個(gè)接口,定義如下:
在DaoAuthenticationProvider的基類???? AbstractUserDetailsAuthenticationProvider發(fā)現(xiàn)以下代碼:
public boolean supports(Class<?> authentication) {return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); }也就是說當(dāng)web表單提交用戶名密碼時(shí),Spring Security由DaoAuthenticationProvider處理。
最后,我們來看一下Authentication(認(rèn)證信息)的結(jié)構(gòu),
它是一個(gè)接口,我們之前提到的UsernamePasswordAuthenticationToken就是它的實(shí)現(xiàn)之一:
(1)Authentication是spring security包中的接口,直接繼承自Principal類,而Principal是位于java.security包中的。它是表示著一個(gè)抽象主體身份,任何主體都有一個(gè)名稱,因此包含一個(gè)getName()方法。
(2)getAuthorities(),權(quán)限信息列表,默認(rèn)是GrantedAuthority接口的一些實(shí)現(xiàn)類,通常是代表權(quán)限信息的一系列字符串。
(3)getCredentials(),憑證信息,用戶輸入的密碼字符串,在認(rèn)證過后通常會(huì)被移除,用于保障安全。
(4)getDetails(),細(xì)節(jié)信息,web應(yīng)用中的實(shí)現(xiàn)接口通常為 WebAuthenticationDetails,它記錄了訪問者的ip地址和sessionId的值。
(5)getPrincipal(),身份信息,大部分情況下返回的是UserDetails接口的實(shí)現(xiàn)類,UserDetails代表用戶的詳細(xì)信息,
?????????? 那從Authentication中取出來的UserDetails就是當(dāng)前登錄用戶信息,它也是框架中的常用接口之一。
UserDetailsService
1)認(rèn)識(shí)UserDetailsService
現(xiàn)在咱們現(xiàn)在知道DaoAuthenticationProvider處理了web表單的認(rèn)證邏輯,認(rèn)證成功后既得到一個(gè)Authentication(UsernamePasswordAuthenticationToken實(shí)現(xiàn)),里面包含了身份信息(Principal)。
這個(gè)身份信息就是一個(gè)Object ,大多數(shù)情況下它可以被強(qiáng)轉(zhuǎn)為UserDetails對(duì)象。
DaoAuthenticationProvider中包含了一個(gè)UserDetailsService實(shí)例,它負(fù)責(zé)根據(jù)用戶名提取用戶信息UserDetails(包含密碼),
而后DaoAuthenticationProvider會(huì)去對(duì)比UserDetailsService提取的用戶密碼與用戶提交的密碼是否匹配作為認(rèn)證成功的關(guān)鍵依據(jù),
因此可以通過將自定義的UserDetailsService 公開為spring bean來定義自定義身份驗(yàn)證。
public interface UserDetailsService {UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }很多人把DaoAuthenticationProvider和UserDetailsService的職責(zé)搞混淆,其實(shí)UserDetailsService只負(fù)責(zé)從特定的地方(通常是數(shù)據(jù)庫)加載用戶信息,僅此而已。
而DaoAuthenticationProvider的職責(zé)更大,它完成完整的認(rèn)證流程,同時(shí)會(huì)把UserDetails填充至Authentication。
上面一直提到UserDetails是用戶信息,咱們看一下它的真面目:
它和Authentication接口很類似,
比如它們都擁有username,authorities。Authentication的getCredentials()與UserDetails中的getPassword()需要被區(qū)分對(duì)待,
前者是用戶提交的密碼憑證,后者是用戶實(shí)際存儲(chǔ)的密碼,認(rèn)證
其實(shí)就是對(duì)這兩者的比對(duì)。
Authentication中的getAuthorities()實(shí)際是由UserDetails的getAuthorities()傳遞而形成的。
還記得Authentication接口中的getDetails()方法嗎?其中的UserDetails用戶詳細(xì)信息便是經(jīng)過了AuthenticationProvider認(rèn)證之后被填充的。
通過實(shí)現(xiàn)UserDetailsService和UserDetails,我們可以完成對(duì)用戶信息獲取方式以及用戶信息字段的擴(kuò)展。
Spring Security提供的InMemoryUserDetailsManager(內(nèi)存認(rèn)證),JdbcUserDetailsManager(jdbc認(rèn)證)就是UserDetailsService的實(shí)現(xiàn)類,主要區(qū)別無非就是從內(nèi)存還是從數(shù)據(jù)庫加載用戶。
總結(jié)
以上是生活随笔為你收集整理的springsecurity的工作原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Security 应用详解
- 下一篇: 报错信息为:Failed to conf