徹底理解瀏覽器同源策略SOP

本文來(lái)自于公眾號(hào)鏈接: 徹底理解瀏覽器同源策略SOP

)

  1. 多種認(rèn)證方式的優(yōu)先級(jí)問(wèn)題瘫镇,如何杜絕沖突的問(wèn)題
  2. 兩個(gè)示例的描述不清晰的問(wèn)題

這是一篇理論和實(shí)戰(zhàn)相結(jié)合的干貨文章,建議手機(jī)閱讀者收藏本文没讲,然后使用電腦下載源碼進(jìn)行實(shí)戰(zhàn)

大綱:

  1. 一.概述
  2. 二.源碼
  3. 三.示例1:接口分多組禽翼,每組認(rèn)證方式不同
  4. 四.示例2:同組接口同時(shí)支持多種認(rèn)證
  5. 五.總結(jié)
  6. 六.參考

一.概述

很多朋友雖然使用Spring Security做過(guò)很多項(xiàng)目捍壤,但是總是感覺(jué)沒(méi)有理解和掌握Spring Security的核心思想续誉。Spring Security比Shiro更強(qiáng)大更靈活的同時(shí),確實(shí)帶來(lái)了一定的復(fù)雜性扛吞。然而這種復(fù)雜性并不是因?yàn)镾pring Security設(shè)計(jì)得不好造成的呻惕,而是因?yàn)榘踩枨蟊旧砭拖褚粓F(tuán)亂麻一樣錯(cuò)綜復(fù)雜,Spring Security成功地將這團(tuán)亂麻梳理柔順后呈現(xiàn)給代價(jià)滥比。在解決復(fù)雜安全問(wèn)題場(chǎng)景下亚脆,Spring Security已經(jīng)足夠簡(jiǎn)潔了,我們更應(yīng)該關(guān)注Spring Security的靈活性盲泛。

認(rèn)證濒持、鑒權(quán)和漏洞防御是安全框架的核心功能。Spring Security的認(rèn)證功能強(qiáng)大并且非常靈活寺滚,支持的認(rèn)證方式也在不斷地水平擴(kuò)展柑营,已經(jīng)預(yù)置了非常多的認(rèn)證方式,如:

  1. Form認(rèn)證
    最常用的(用戶名/密碼)認(rèn)證方式及其變體玛迄,如(手機(jī)號(hào)/驗(yàn)證碼)
    插圖:用戶名密碼
  2. HTTP BASIC認(rèn)證
    插圖:瀏覽器彈出框
  3. LDAP認(rèn)證
    大型環(huán)境如企業(yè)用戶經(jīng)常采用LDAP
  4. CAS認(rèn)證
    單點(diǎn)登錄場(chǎng)景下常用解決方案
  5. HTTP Digest 認(rèn)證頭 ( IETF RFC-based 標(biāo)準(zhǔn))
  6. HTTP X.509 客戶端證書交換 ( IETF RFC-based 標(biāo)準(zhǔn))
  7. OpenID 認(rèn)證
  8. ......

如果預(yù)置的認(rèn)證仍然不滿足需求由境,Spring Security支持用戶自定義認(rèn)證方式。

除了認(rèn)證方式的豐富性蓖议,Spring Security對(duì)認(rèn)證的配置也非常靈活。Spring Security支持多種認(rèn)證方式自由組合讥蟆。

本文主要通過(guò)兩個(gè)代碼示例來(lái)展示Spring Security認(rèn)證的靈活性:

  • 第一個(gè)配置示例: 接口分多組勒虾,每組認(rèn)證方式不同
  • 第二個(gè)配置示例: 同組接口同時(shí)支持多種認(rèn)證

二.源碼

本文源碼維護(hù)在Github,非常具有參考價(jià)值瘸彤,建議下載源碼:

有兩個(gè)模塊:

插圖: twomodule

  • spring-security-url-separate-sample: 本文展示Spring Security認(rèn)證的靈活性的配置示例修然。
  • authorizationserver:自建的OAuth2認(rèn)證服務(wù)器。

三.示例1:接口分多組,每組認(rèn)證方式不同

假設(shè)一個(gè)web應(yīng)用的一部分接口是暴露在互聯(lián)網(wǎng)上提供服務(wù)API接口愕宋,而另一部分接口是只需內(nèi)部訪問(wèn)的內(nèi)部接口玻靡。我們常常把這個(gè)web應(yīng)用配置為OAuth2資源服務(wù)器,其中API接口采用OAuth2資源服務(wù)歐認(rèn)證中贝,內(nèi)部接口則采用傳統(tǒng)的認(rèn)證方式如Form認(rèn)證囤捻。
Spring Security支持這種“接口分多組,每組認(rèn)證方式不同”類型的需求邻寿。

1.新建Spring Boot工程

新建Spring Boot工程蝎土,命名為“spring-security-url-separate-sample”,依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

spring-boot-starter-oauth2-resource-server是OAuth2資源服務(wù)器功能包绣否。

2.增加兩個(gè)Controller

FooController:

@RestController
public class FooController {

    @GetMapping("/foo")
    public String getSample() {
        return "get foo";
    }
}

和BarController:

@RestController
public class BarController {

    @GetMapping("/bar")
    public String getSample() {
        return "get bar";
    }
}

兩個(gè)Controller用來(lái)模擬兩組API接口誊涯。

3.兩個(gè)Spring Security配置類

GroupOneSecurityConfig配置所有以“/foo”開頭的接口使用OAuth2資源服務(wù)進(jìn)行認(rèn)證和鑒權(quán):

@Configuration
//此處配置Order=1,因而比 GroupTwoSecurityConfig 配置類先執(zhí)行蒜撮,配置優(yōu)先級(jí)高暴构,因?yàn)镾pring Security的配置規(guī)則是"先執(zhí)行的優(yōu)先級(jí)高"。
@Order(1)
public class GroupOneSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers()
                .antMatchers("/foo/**")
                .and().authorizeRequests().anyRequest().fullyAuthenticated()
                .and().oauth2ResourceServer().jwt();
    }
}

GroupTwoSecurityConfig配置除了以“/foo”開頭的接口外剩余的其他接口使用From認(rèn)證:

@EnableWebSecurity(debug = true)
public class GroupTwoSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/error", "/login**").permitAll()
                .anyRequest().fullyAuthenticated()
                .and().formLogin();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password(passwordEncoder().encode("123456"))
                .roles("ADMIN", "USER");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

GroupTwoSecurityConfig類配置的接口選擇范圍為“所有接口”段磨,包含了GroupOneSecurityConfig選擇的以“/foo”開頭的接口取逾,但是不用擔(dān)心兩個(gè)配置類的范圍沖突問(wèn)題,因?yàn)槲覀冊(cè)?GroupOneSecurityConfig上增加了@Order(1)注解薇溃。@Order表示執(zhí)行優(yōu)先級(jí)菌赖,WebSecurityConfigurerAdapter默認(rèn)的優(yōu)先級(jí)是100:
插圖:order

Spring Security的@Order規(guī)則是:“數(shù)字越小,越先執(zhí)行沐序,并且先執(zhí)行的配置優(yōu)先級(jí)高”琉用。
@Order(1)小于默認(rèn)的@Order(100),所以GroupOneSecurityConfig的接口選擇“/foo”的優(yōu)先級(jí)高策幼、先生效邑时,而GroupTwoSecurityConfig只能選擇到除“/foo”以外剩余的接口。

工程的接口分為了兩組:

  1. 以“/foo”開頭的接口特姐,使用OAuth2資源服務(wù)認(rèn)證
  2. 除“/foo”開頭接口外剩余的接口晶丘,使用From認(rèn)證。

注意GroupTwoSecurityConfig要配置“/error”和“/login**”為permitAll()

4.配置文件

server:
  servlet:
    session:
      cookie:
        name: UISESSIONCOUPON

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: http://localhost:9999/.well-known/jwks.json

自建OAuth2認(rèn)證服務(wù)器和本工程都以localhost啟動(dòng)唐含,配置不同的cookie名稱浅浮,防止沖突報(bào)錯(cuò),并且使用JWK接口驗(yàn)證 JWT Token 的有效性捷枯。

5.運(yùn)行與演示

假設(shè)spring-security-url-separate-sample是一個(gè)在互聯(lián)網(wǎng)提供API接口的服務(wù)器滚秩,其中“/foo”接口暴露在互聯(lián)網(wǎng)提供服務(wù)的API接口,而 “/bar”接口為內(nèi)部接口淮捆,則有如下訪問(wèn)場(chǎng)景:

  1. 內(nèi)部接口可以直接使用Form認(rèn)證
    1. 啟動(dòng)“spring-security-url-separate-sample”
    2. 隱身模式打開瀏覽器郁油,輸入:http://localhost:8080/bar
      插圖:formlogin
    3. 輸入用戶名/密碼:admin/123456本股,可以登錄成功
    4. 瀏覽器再輸入:http://localhost:8080/foo ,也可以成功返回字符串“get foo”桐腌。
      用戶使用Form登錄后既可以訪問(wèn)API接口也可以訪問(wèn)內(nèi)部接口拄显。
  2. 暴露在互聯(lián)網(wǎng)的API接口只能使用OAuth2資源服務(wù)認(rèn)證:隨便來(lái)自于互聯(lián)網(wǎng)的用戶不能獲得內(nèi)部的用戶名和密碼
    1. 啟動(dòng)“spring-security-url-separate-sample”

    2. 啟動(dòng)“sauthorizationserver”

    3. 隱身模式打開瀏覽器,輸入:http://localhost:8080/foo
      插圖:foo401
      未認(rèn)證時(shí)案站,OAuth2資源服務(wù)認(rèn)證不會(huì)自動(dòng)重定向到認(rèn)證中心躬审,而是顯示要401錯(cuò)誤嘶朱。調(diào)用
      “/foo”接口是需要攜帶OAuth2的access token的跺涤。

    4. 使用curl命令行工具模擬OAuth2請(qǐng)求,使用密碼模式獲取一個(gè)access token:

      curl -i -X POST -d "username=admin&password=admin&grant_type=password&client_id=client-for-server&client_secret=client-for-server" http://localhost:9999/oauth/token
      

      插圖:gettoken

    5. 攜帶access_token請(qǐng)求“/foo”接口:

      curl -i -H "Authorization:Bearer {此處粘貼上一步驟返回的access_token}"  http://localhost:8080/foo
      

      插圖:foosuccess
      外部用戶成功調(diào)用“/foo”接口昂灵,但是仍然無(wú)法調(diào)用到內(nèi)部“/bar”接口舱禽。內(nèi)部接口”被成功地保護(hù)起來(lái)了炒刁。

此示例將應(yīng)用接口分為兩組,分別使用不同的認(rèn)證方式誊稚。理論上Spring Security可以將接口分為任意多組翔始,使用任意多種認(rèn)證方式,非常靈活里伯。

四.示例2:同組接口同時(shí)支持多種認(rèn)證

除了多組接口使用不同的認(rèn)證方式外城瞎。對(duì)于同一組接口,可以同時(shí)支持多種認(rèn)證方式疾瓮。

我們繼續(xù)對(duì)“spring-security-url-separate-sample”進(jìn)行擴(kuò)展脖镀。

1.增加OAuth2 Client依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

2.在GroupTwoSecurityConfig中增加配置

@Override
public void configure(HttpSecurity http) throws Exception {
   ...
   .and().formLogin()
   .and().oauth2Login();
}

對(duì)于除“/foo"以外的其他接口同時(shí)支持Form認(rèn)證和OAuth2客戶端認(rèn)證。

3.配置文件增加配置

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: b7fb29a538bb19b09365
            client-secret: 2fbfd22e69e61d873bad55143538770748a76d3a
          custom:
            client-id: client-for-server
            client-secret: client-for-server
            provider: custom
            client-name: 自建OAuth2認(rèn)證服務(wù)
            authorization-grant-type: authorization_code
            redirect-uri: "http://localhost:8080/login/oauth2/code/custom"
        provider:
          custom:
            authorization-uri: http://localhost:9999/oauth/authorize
            token-uri: http://localhost:9999/oauth/token
            user-info-uri: http://localhost:9999/me
            user-name-attribute: "name"
            jwk-set-uri: http://localhost:9999/.well-known/jwks.json

配置兩個(gè)OAuth2客戶端狼电,一個(gè)是Github的OAuth2的客戶端蜒灰,另一是自建OAuth2認(rèn)證服務(wù)器的客戶端。

4.運(yùn)行與演示

對(duì)于“/bar”接口肩碟,同時(shí)支持Form認(rèn)證和OAuth2客戶端認(rèn)證强窖。

  1. 啟動(dòng)“spring-security-url-separate-sample”
  2. 啟動(dòng)“sauthorizationserver”
  3. 隱身模式打開瀏覽器,輸入:http://localhost:8080/bar
    插圖:oauth2login
    此時(shí)我們有三種選擇:
    1. 輸入用戶名/密碼:admin/123456登錄成功削祈。
    2. 點(diǎn)擊“Github”藍(lán)色按鈕翅溺,使用Github賬號(hào)登錄成功。
    3. 點(diǎn)擊“自建OAuth2認(rèn)證服務(wù)”藍(lán)色按鈕髓抑,使用自建OAuth2認(rèn)證服務(wù)咙崎,輸入用戶名/密碼;admin/admin吨拍,登錄成功叙凡。
      插圖: customas

此示例演示了Spring Security支持同組接口同時(shí)支持多種認(rèn)證

五.總結(jié)

spring-security-url-separate-sample整體來(lái)看同時(shí)支持了Form密末、GitHub認(rèn)證握爷、自建OAuth2認(rèn)證服務(wù)客戶端認(rèn)證和自建OAuth2認(rèn)證服務(wù)資源服務(wù)認(rèn)證四種認(rèn)證方式,并且不互相沖突严里。每種認(rèn)證方式都有各自的應(yīng)用場(chǎng)景新啼。

Spring Security實(shí)現(xiàn)之所以可以實(shí)現(xiàn)如此靈活的認(rèn)證配置,正是因?yàn)椤鞍葱柩b配”這一核心思想刹碾。

首先無(wú)論Spring Security應(yīng)用在Servlet還是響應(yīng)式(Reactive)場(chǎng)景燥撞,都是一種AOP切面原理。
插圖:authenticaiton

其次一個(gè)web應(yīng)用根據(jù)需求迷帜,需要使用哪種認(rèn)證方式就裝配哪種物舒。
插圖;asneed

總之戏锹,Spring Security除了支持漏洞防御冠胯,針對(duì)認(rèn)證和鑒權(quán)的需求做了的非常強(qiáng)大且靈活的設(shè)計(jì)。

本文的相關(guān)源碼上傳到了Github锦针,地址:https://github.com/andyzhaozhao/spring-security-url-separate

如果有任何問(wèn)題和建議荠察,可以右下角點(diǎn)贊后評(píng)論,我們會(huì)第一時(shí)間回復(fù)奈搜。

六.參考

更多干貨都在《spring security實(shí)戰(zhàn)》

本為官方出處微信公眾號(hào): 碼聞


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末悉盆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子馋吗,更是在濱河造成了極大的恐慌焕盟,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宏粤,死亡現(xiàn)場(chǎng)離奇詭異脚翘,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)商架,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門堰怨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蛇摸,你說(shuō)我怎么就攤上這事备图。” “怎么了赶袄?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵揽涮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我饿肺,道長(zhǎng)蒋困,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任敬辣,我火速辦了婚禮雪标,結(jié)果婚禮上零院,老公的妹妹穿的比我還像新娘。我一直安慰自己村刨,他們只是感情好告抄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嵌牺,像睡著了一般打洼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逆粹,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天募疮,我揣著相機(jī)與錄音,去河邊找鬼僻弹。 笑死阿浓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奢方。 我是一名探鬼主播搔扁,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蟋字!你這毒婦竟也來(lái)了稿蹲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鹊奖,失蹤者是張志新(化名)和其女友劉穎苛聘,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忠聚,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡设哗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了两蟀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片网梢。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖赂毯,靈堂內(nèi)的尸體忽然破棺而出战虏,到底是詐尸還是另有隱情,我是刑警寧澤党涕,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布烦感,位于F島的核電站,受9級(jí)特大地震影響膛堤,放射性物質(zhì)發(fā)生泄漏手趣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一肥荔、第九天 我趴在偏房一處隱蔽的房頂上張望绿渣。 院中可真熱鬧朝群,春花似錦、人聲如沸怯晕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)舟茶。三九已至,卻和暖如春堵第,著一層夾襖步出監(jiān)牢的瞬間吧凉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工踏志, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留阀捅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓针余,卻偏偏與公主長(zhǎng)得像饲鄙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子圆雁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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