Spring Security

本文基于 Spring Security 5.3版本
官方文檔

一框杜、簡介

Spring Security是一個提供身份驗證,授權(quán)和保護以防止常見攻擊的框架塑陵。 憑借對命令式和響應(yīng)式應(yīng)用程序的一流支持傻工,它是用于保護基于Spring的應(yīng)用程序的實際標(biāo)準(zhǔn)鲜戒。
Spring Security通過標(biāo)準(zhǔn)的Filter與servlet容器進行集成师幕,所以粟按,只要是符合servlet規(guī)范的容器都可以用Spring Servlet進行保護。

Spring Security需要Java 8或更高版本的運行時環(huán)境霹粥。

二灭将、引入Spring Security

文檔中介紹了使用springboot和不使用springboot集成的方法,這里只介紹使用springboot的方式(采用maven)

新建springboot項目(版本2.2.4)引入maven坐標(biāo)

<dependencies>
   <!-- ... other dependency elements ... -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-security</artifactId>
   </dependency>
</dependencies>

三后控、Spring Security模塊劃分

在Spring Security 3.0中庙曙,代碼庫被細(xì)分為單獨的jar,這些jar更清楚地區(qū)分了不同的功能區(qū)域和第三方依賴項忆蚀。

1.Core?—?spring-security-core.jar

該模塊包含核心身份驗證和訪問控制類和接口矾利,遠程支持和基本配置API姑裂。 使用Spring Security的任何應(yīng)用程序都需要它馋袜。 它支持獨立的應(yīng)用程序,遠程客戶端舶斧,方法(服務(wù)層)安全性和JDBC用戶配置欣鳖。 它包含以下頂級程序包

  • org.springframework.security.core
  • org.springframework.security.access
  • org.springframework.security.authentication
  • org.springframework.security.provisioning

2.Remoting?—?spring-security-remoting.jar

該模塊提供了與Spring Remoting的集成。 除非您要編寫使用Spring Remoting的遠程客戶端茴厉,否則您不需要關(guān)注泽台。

3.Web?—?spring-security-web.jar

該模塊包含過濾器和相關(guān)的Web安全基礎(chǔ)結(jié)構(gòu)代碼。 它包含任何與Servlet API相關(guān)的內(nèi)容矾缓。 如果需要Spring Security Web認(rèn)證服務(wù)和基于URL的訪問控制怀酷,則需要它。 主要軟件包是org.springframework.security.web嗜闻。

4.Config?—?spring-security-config.jar

該模塊包含安全名稱空間解析代碼和Java配置代碼蜕依。 如果您使用Spring Security XML名稱空間進行配置或Spring Security的Java配置支持,則需要它

5.LDAP?—?spring-security-ldap.jar

該模塊提供LDAP身份驗證和供應(yīng)代碼琉雳。 如果您需要使用LDAP認(rèn)證或管理LDAP用戶條目样眠,則為必填項

6. OAuth 2.0 Core?—?spring-security-oauth2-core.jar

spring-security-oauth2-core.jar包含核心類和接口,這些類和接口提供對OAuth 2.0授權(quán)框架和OpenID Connect Core 1.0的支持翠肘。 使用OAuth 2.0或OpenID Connect Core 1.0的應(yīng)用程序(例如客戶端檐束,資源服務(wù)器和授權(quán)服務(wù)器)需要它

7.OAuth 2.0 Client?—?spring-security-oauth2-client.jar

包含Spring Security對OAuth 2.0授權(quán)框架和OpenID Connect Core 1.0的客戶端支持。 使用OAuth 2.0登錄或OAuth客戶端支持的應(yīng)用程序需要使用它

8.OAuth 2.0 JOSE?—?spring-security-oauth2-jose.jar

包含Spring Security對JOSE(Javascript對象簽名和加密)框架的支持束倍。 JOSE框架旨在提供一種在各方之間安全地轉(zhuǎn)移索賠的方法被丧。 它是根據(jù)一系列規(guī)范構(gòu)建的:

  • JSON Web Token (JWT)
  • JSON Web Signature (JWS)
  • JSON Web Encryption (JWE)
  • JSON Web Key (JWK)

9. OAuth 2.0 Resource Server?—?spring-security-oauth2-resource-server.jar

包含Spring Security對OAuth 2.0資源服務(wù)器的支持盟戏。 它用于通過OAuth 2.0承載令牌保護API

10.ACL?—?spring-security-acl.jar

該模塊包含專門的域?qū)ο驛CL實現(xiàn)。 它用于將安全性應(yīng)用于應(yīng)用程序中的特定域?qū)ο髮嵗?/p>

11.CAS?—?spring-security-cas.jar

該模塊包含Spring Security的CAS客戶端集成晚碾。 如果要對CAS單點登錄服務(wù)器使用Spring Security Web認(rèn)證抓半,則應(yīng)該使用它。

12.OpenID?—?spring-security-openid.jar

該模塊包含OpenID Web身份驗證支持格嘁。 它用于根據(jù)外部OpenID服務(wù)器對用戶進行身份驗證

13.Test?—?spring-security-test.jar

該模塊包含對使用Spring Security進行測試的支持

四笛求、Spring Boot 關(guān)于Spring Security的自動配置

1. springSecurityFilterChain

自動配置會在servlet容器中創(chuàng)建一個名為springSecurityFilterChain的過濾器,負(fù)責(zé)應(yīng)用程序內(nèi)的所有安全性(保護應(yīng)用程序URL糕簿,驗證提交的用戶名和密碼探入,重定向到登錄表單等)


image.png

2. UserDetailsS??ervice

自動配置會創(chuàng)建一個UserDetailsS??ervice實例,其中包含用戶名user和一個隨機生成的密碼懂诗,該密碼將記錄到控制臺

3. springSecurityFilterChain會作為標(biāo)準(zhǔn)的Filter注冊到Servlet容器中蜂嗽,每個請求都會經(jīng)過它被處理

4. 其他自動完成的配置

五殃恒、Spring Security整體架構(gòu)設(shè)計

1.FilterChain

首先是spring security的FilterChain里面包含很多spring security內(nèi)部的過濾器植旧,并且過濾器的順序是固定的

image.png
2.DelegatingFilterProxy

Spring提供了一個名為DelegatingFilterProxy的Filter實現(xiàn),可以在Servlet容器的生命周期和Spring的ApplicationContext之間進行橋接离唐。 Servlet容器允許使用其自己的標(biāo)準(zhǔn)注冊Filters病附,但它不了解Spring定義的Bean。 DelegatingFilterProxy可以通過標(biāo)準(zhǔn)的Servlet容器機制進行注冊亥鬓,但是可以將所有工作委托給實現(xiàn)Filter的Spring Bean完沪。


image.png

DelegatingFilterProxy的作用可以用下面的偽代碼表示

public void doFilter(ServletRequest request, 
ServletResponse response, FilterChain chain) {
// Lazily get Filter that was registered as a Spring Bean 
 // For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
 Filter delegate = getFilterBean(someBeanName);
 // delegate work to the Spring Bean 
 delegate.doFilter(request, response);

}

DelegatingFilterProxy的另一個好處是它允許延遲查找Filter bean實例。 這很重要嵌戈,因為容器需要在容器啟動之前注冊Filter實例覆积。 但是,Spring通常使用ContextLoaderListener加載Spring Bean熟呛,直到需要注冊Filter實例之后才可以加載宽档。

3.FilterChainProxy

Spring Security的Servlet支持包含在FilterChainProxy中。 FilterChainProxy是Spring Security提供的特殊過濾器庵朝,允許通過SecurityFilterChain委派許多過濾器實例吗冤。 由于FilterChainProxy是Bean,因此通常將其包裝在DelegatingFilterProxy中偿短。


image.png

4.SecurityFilterChain

FilterChainProxy使用SecurityFilterChain確定應(yīng)對此請求調(diào)用哪些Spring Security過濾器欣孤。


image.png

5. Security Filters

SecurityFilterChain 中包含很多個Filter,這些Filter裝載到SecurityFilterChain中昔逗, SecurityFilterChain再裝載到FilterChainProxy中降传,F(xiàn)ilterChainProxy再被裝載到連接Servlet容器和spring容器的DelegatingFilterProxy中。
包含以下這些過濾器:

  • ChannelProcessingFilter

  • ConcurrentSessionFilter

  • WebAsyncManagerIntegrationFilter

  • SecurityContextPersistenceFilter

  • HeaderWriterFilter

  • CorsFilter

  • CsrfFilter

  • LogoutFilter

  • OAuth2AuthorizationRequestRedirectFilter

  • Saml2WebSsoAuthenticationRequestFilter

  • X509AuthenticationFilter

  • AbstractPreAuthenticatedProcessingFilter

  • CasAuthenticationFilter

  • OAuth2LoginAuthenticationFilter

  • Saml2WebSsoAuthenticationFilter

  • UsernamePasswordAuthenticationFilter

  • ConcurrentSessionFilter

  • OpenIDAuthenticationFilter

  • DefaultLoginPageGeneratingFilter

  • DefaultLogoutPageGeneratingFilter

  • DigestAuthenticationFilter

  • BearerTokenAuthenticationFilter

  • BasicAuthenticationFilter

  • RequestCacheAwareFilter

  • SecurityContextHolderAwareRequestFilter

  • JaasApiIntegrationFilter

  • RememberMeAuthenticationFilter

  • AnonymousAuthenticationFilter

  • OAuth2AuthorizationCodeGrantFilter

  • SessionManagementFilter

  • ExceptionTranslationFilter

  • FilterSecurityInterceptor

  • SwitchUserFilter

6.Handling Security Exceptions

ExceptionTranslationFilter允許將AccessDeniedException和AuthenticationException轉(zhuǎn)換為HTTP響應(yīng)勾怒。它也是上面介紹的過濾器鏈中的一個


image.png

①開始處理
②如果用戶未通過身份驗證或拋出AuthenticationException婆排,則啟動身份驗證声旺。
③如果拋出AccessDeniedException,則拒絕訪問段只。 調(diào)用AccessDeniedHandler以處理拒絕的訪問

六腮猖、認(rèn)證方式

1. 認(rèn)證模塊的組件

  • SecurityContextHolder:Spring Security在其中存儲通過身份驗證的人員的詳細(xì)信息


    image.png
  • SecurityContext:從SecurityContextHolder獲得,并包含當(dāng)前經(jīng)過身份驗證的用戶的身份驗證

  • Authentication
    兩個主要用途:
    1.作為AuthenticationManager的輸入赞枕,用于提供用戶提供的用于身份驗證的憑據(jù)
    2.代表當(dāng)前經(jīng)過身份驗證的用戶澈缺。 可以從SecurityContext獲得當(dāng)前的身份驗證

  • GrantedAuthority:授予身份驗證主體的權(quán)限(即角色,作用域等)

  • AuthenticationManager:AuthenticationManager是用于定義Spring Security的過濾器如何執(zhí)行身份驗證的API炕婶。 然后姐赡,由調(diào)用AuthenticationManager的控制器(即Spring Security的Filters)在SecurityContextHolder上設(shè)置返回的身份驗證。 如果您沒有與Spring Security的過濾器集成柠掂,則可以直接設(shè)置
    SecurityContextHolder项滑,并且不需要使用AuthenticationManager。雖然AuthenticationManager的實現(xiàn)可以是任何東西涯贞,但最常見的實現(xiàn)是ProviderManager枪狂。

  • ProviderManager:AuthenticationManager的最常見實現(xiàn),ProviderManager將認(rèn)證工作委托給AuthenticationProviders列表宋渔, 每個AuthenticationProvider都有機會指示認(rèn)證應(yīng)該成功州疾,失敗,或者表明它不能做出決定并允許下一個AuthenticationProvider進行決定傻谁。 如果沒有一個已配置的AuthenticationProviders可以進行身份驗證孝治,則身份驗證將失敗列粪,并顯示ProviderNotFoundException审磁,這是一個特殊的AuthenticationException,它指示未配置ProviderManager并支持傳遞給它的Authentication類型岂座。


    image.png

七态蒂、 Username/Password Authentication(用戶名密碼認(rèn)證方式)

由于這個認(rèn)證組件部分內(nèi)容筆記多,單獨拉出來說明
Spring Security提供了以下內(nèi)置機制费什,用于從HttpServletRequest中讀取用戶名和密碼
1.Form Login
2.Basic Authentication
3.Digest Authentication

1.表單登錄方式
image.png

該圖基于我們的SecurityFilterChain圖钾恢。

①用戶對未經(jīng)授權(quán)的資源/ private進行未經(jīng)身份驗證的請求。

②Spring Security的FilterSecurityInterceptor表示通過拋出AccessDeniedException拒絕了未經(jīng)身份驗證的請求鸳址。

③由于用戶未通過身份驗證瘩蚪,因此ExceptionTranslationFilter會啟動“開始身份驗證”,并使用配置的AuthenticationEntryPoint將重定向發(fā)送到登錄頁面稿黍。 在大多數(shù)情況下疹瘦,AuthenticationEntryPoint是LoginUrlAuthenticationEntryPoint的實例。

④然后巡球,瀏覽器將請求將其重定向到的登錄頁面言沐。

⑤應(yīng)用程序中的某些內(nèi)容必須呈現(xiàn)登錄頁面邓嘹。

提交用戶名和密碼后,UsernamePasswordAuthenticationFilter會對用戶名和密碼進行身份驗證

image.png

①當(dāng)用戶提交其用戶名和密碼時险胰,UsernamePasswordAuthenticationFilter通過從HttpServletRequest中提取用戶名和密碼來創(chuàng)建UsernamePasswordAuthenticationToken汹押,這是一種身份驗證類型。

②接下來起便,將UsernamePasswordAuthenticationToken傳遞到AuthenticationManager進行身份驗證棚贾。 AuthenticationManager外觀的詳細(xì)信息取決于用戶信息的存儲方式。

③如果身份驗證失敗榆综,則失敗

  • 清除SecurityContextHolder鸟悴。
  • RememberMeServices.loginFail被調(diào)用。如果記住我沒有配置奖年,這是一個禁忌细诸。
  • AuthenticationFailureHandler被調(diào)用。

④如果身份驗證成功陋守,則為成功震贵。

  • 新的登錄通知SessionAuthenticationStrategy。
  • 身份驗證是在SecurityContextHolder上設(shè)置的水评。
  • RememberMeServices.loginSuccess被調(diào)用猩系。如果記住我沒有配置,這是一個禁忌中燥。
  • ApplicationEventPublisher發(fā)布一個
  • InteractiveAuthenticationSuccessEvent寇甸。
  • AuthenticationSuccessHandler被調(diào)用。通常疗涉,這是一個SimpleUrlAuthenticationSuccessHandler拿霉,當(dāng)我們重定向到登錄頁面時,它將重定向到ExceptionTranslationFilter保存的請求咱扣。
  • AuthenticationProvider:
    可以將多個AuthenticationProviders注入ProviderManager绽淘。 每個AuthenticationProvider執(zhí)行特定的身份驗證類型。
    例如闹伪,DaoAuthenticationProvider支持基于用戶名/密碼的身份驗證沪铭,而JwtAuthenticationProvider支持對JWT令牌的身份驗證。
  • 帶AuthenticationEntryPoint的請求憑據(jù):用于從客戶端請求憑據(jù)(即偏瓤,重定向到登錄頁面杀怠,發(fā)送WWW身份驗證響應(yīng)等)
  • AbstractAuthenticationProcessingFilter:用于身份驗證的基本過濾器


    image.png
2.Basic Authentication
image.png

該圖基于我們的SecurityFilterChain圖。

①用戶對未經(jīng)授權(quán)的資源發(fā)起請求厅克。
②Spring Security的FilterSecurityInterceptor表示通過拋出AccessDeniedException拒絕了未經(jīng)身份驗證的請求赔退。
③由于用戶未通過身份驗證,因此ExceptionTranslationFilter會啟動“開始身份驗證”已骇。 配置的AuthenticationEntryPoint是BasicAuthenticationEntryPoint的實例离钝,該實例響應(yīng)WWW-Authenticate頭票编。 RequestCache通常是一個NullRequestCache,它不保存請求卵渴,因為客戶端能夠重播它最初請求的請求慧域。
當(dāng)客戶端收到WWW-Authenticate響應(yīng)頭時,它知道應(yīng)該使用用戶名和密碼重試浪读。 以下是正在處理的用戶名和密碼的流程昔榴。


image.png

①當(dāng)用戶提交其用戶名和密碼時,BasicAuthenticationFilter通過從HttpServletRequest中提取用戶名和密碼來創(chuàng)建UsernamePasswordAuthenticationToken碘橘,這是一種身份驗證類型互订。
②接下來,將UsernamePasswordAuthenticationToken傳遞到AuthenticationManager進行身份驗證痘拆。
③如果身份驗證失敗仰禽,則失敗,清除SecurityContextHolder存儲纺蛆,RememberMeServices.loginFail被調(diào)用吐葵。
調(diào)用AuthenticationEntryPoint觸發(fā)WWW-Authenticate重新發(fā)送。
④如果身份驗證成功桥氏,則為成功温峭,向SecurityContextHolder存儲登錄成功信息
RememberMeServices.loginSuccess被調(diào)用
BasicAuthenticationFilter調(diào)用FilterChain.doFilter(request,response)繼續(xù)進行其余的應(yīng)用程序邏輯字支。

Spring Security的HTTP基本身份驗證支持默認(rèn)為啟用凤藏。 但是,一旦提供了任何基于servlet的配置堕伪,則必須顯式提供HTTP Basic
如下

protected void configure(HttpSecurity http) {
    http
        // ...
        .httpBasic(withDefaults());
}

3.Digest Authentication

4.In-Memory Authentication

springsecurity支持在內(nèi)存中臨時設(shè)置用戶信息完成認(rèn)證
可以按實例進行設(shè)置,定義兩個用戶并設(shè)置權(quán)限

@Bean
public UserDetailsService users() {
    UserDetails user = User.builder()
        .username("user")
        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
        .roles("USER")
        .build();
    UserDetails admin = User.builder()
        .username("admin")
        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
        .roles("USER", "ADMIN")
        .build();
    return new InMemoryUserDetailsManager(user, admin);
}

5. JDBC Authentication

支持從數(shù)據(jù)庫查詢用戶信息完成認(rèn)證

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揖庄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子刃跛,更是在濱河造成了極大的恐慌抠艾,老刑警劉巖苛萎,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桨昙,死亡現(xiàn)場離奇詭異,居然都是意外死亡腌歉,警方通過查閱死者的電腦和手機蛙酪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翘盖,“玉大人桂塞,你說我怎么就攤上這事♀裳保” “怎么了阁危?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵玛痊,是天一觀的道長。 經(jīng)常有香客問我狂打,道長擂煞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任趴乡,我火速辦了婚禮对省,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘晾捏。我一直安慰自己蒿涎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布惦辛。 她就那樣靜靜地躺著劳秋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胖齐。 梳的紋絲不亂的頭發(fā)上俗批,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音市怎,去河邊找鬼岁忘。 笑死,一個胖子當(dāng)著我的面吹牛区匠,可吹牛的內(nèi)容都是我干的干像。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼驰弄,長吁一口氣:“原來是場噩夢啊……” “哼麻汰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起戚篙,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤五鲫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后岔擂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體位喂,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年乱灵,在試婚紗的時候發(fā)現(xiàn)自己被綠了塑崖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡痛倚,死狀恐怖规婆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤抒蚜,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布掘鄙,位于F島的核電站,受9級特大地震影響嗡髓,放射性物質(zhì)發(fā)生泄漏通铲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一器贩、第九天 我趴在偏房一處隱蔽的房頂上張望颅夺。 院中可真熱鬧,春花似錦蛹稍、人聲如沸吧黄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拗慨。三九已至,卻和暖如春奉芦,著一層夾襖步出監(jiān)牢的瞬間赵抢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工声功, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留烦却,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓先巴,卻偏偏與公主長得像其爵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伸蚯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345