自定義SpringSecurity認(rèn)證方式

就理論而言,理論和實(shí)踐并無(wú)差異励两,但真付諸實(shí)行,差異即開(kāi)始顯現(xiàn)囊颅。


Jan?L.A van de Snepscheut


我們?cè)谲浖_(kāi)發(fā)過(guò)程中当悔,需要針對(duì)不同的軟件產(chǎn)品需求傅瞻,提供不同的身份認(rèn)證方式,縱使SpringSecurity非常強(qiáng)大盲憎,她所提供的身份認(rèn)證方式也不足以面對(duì)各式各樣的身份認(rèn)證方式嗅骄,所以學(xué)習(xí)如何擴(kuò)展SpringSecurity的認(rèn)證方式也就非常有必要了。


注意焙畔!這不是一篇對(duì)于SpringSecurity毫無(wú)了解的讀者準(zhǔn)備的掸读,所以在閱讀這篇文章之前你需要了解對(duì)SpringSecurity有一些基礎(chǔ)的了解。


“ Spring Security的認(rèn)證流程

在我們自定義SpringSecurity的認(rèn)證方式之前宏多,先從SpringSecurity的用戶(hù)名/密碼認(rèn)證中了解SpringSecurity的認(rèn)證流程儿惫,以及參與到這個(gè)流程的類(lèi)它們各自的職責(zé)是什么。

用戶(hù)名/密碼認(rèn)證流程(SecurityFilterChain中每一個(gè)橙色矩形條代表一個(gè)SecurityFilter伸但,因?yàn)檫@里主要講解用戶(hù)名/密碼認(rèn)證肾请,故突出顯示UsernamePasswordAuthenticationFilter)


  • 當(dāng)用戶(hù)提交他們的用戶(hù)名和密碼時(shí),這個(gè)UsernamePasswordAuthenticationFilter會(huì)從HttpServletRequest提取用戶(hù)名和密碼更胖,然后使用提取出的用戶(hù)名和密碼創(chuàng)建UsernamePasswordAuthenticationToken铛铁。

  • 接下來(lái)該UsernamePasswordAuthenticationToken會(huì)作為AuthenticationManager.authentication(通常是調(diào)用AuthenticationManager的一個(gè)實(shí)現(xiàn)類(lèi)ProviderManager重寫(xiě)的authentication方法)方法的參數(shù)傳入。

  • ProviderManager從它所擁有的AuthenticationProvider的列表中找到一個(gè)支持認(rèn)證UsernamePasswordAuthenticationToken的一個(gè)AuthenticationProvider(在這里是如右圖的DaoAuthenticationProvider)却妨。

  • DaoAuthenticationProvider會(huì)通過(guò)UserDetailsService類(lèi)使用UsernamePasswordAuthenticationToken中username去查詢(xún)用戶(hù)饵逐,然后對(duì)該用戶(hù)進(jìn)行身份認(rèn)證。

  • 如果認(rèn)證失敱氡辍:

  • SecurityContextHolder被清空倍权。

  • RememberMeServices.loginFail會(huì)被調(diào)用,如果rememberme沒(méi)有被配置捞烟,將不會(huì)有任何操作薄声。

  • AuthenticationFailureHandler被調(diào)用。

  • 如果認(rèn)證成功:

  • SessionAuthenticationStrategy會(huì)收到一個(gè)登錄通知题画。

  • 這個(gè)Authencation會(huì)被放置到SecurityContextHolder中默辨,RememberMeServices.loginSuccess將被調(diào)用。

  • 如果沒(méi)有設(shè)置rememberme苍息,將不會(huì)有任何操作缩幸。

  • ApplicationEventPublisher發(fā)布一個(gè)InteractiveAuthenticationSuccessEvent。


  • 從上述的用戶(hù)名/密碼認(rèn)證的流程中竞思,我們可以得出如下圖所示的一個(gè)通用流程桌粉。

    抽象認(rèn)證流程

  • 當(dāng)用戶(hù)提交他們的憑證的時(shí)候,AbstractAuthenticationProcessingFilter會(huì)從HttpServletRequest提取相關(guān)的數(shù)據(jù)創(chuàng)建一個(gè)Authentication去認(rèn)證衙四。這個(gè)被創(chuàng)建的Authentication的類(lèi)型取決于AbstractAuthenticationProcessingFilter的子類(lèi)(例如铃肯,UsernamePasswordAuthenticationFilter就是從被提交的HttpServletRequest中提取出用戶(hù)名和密碼,然后創(chuàng)建了UsernamePasswordAuthenticationToken)传蹈。
  • 接下來(lái)押逼,這個(gè)Authentication被傳入AuthenticationManager去認(rèn)證,然后AuthenticationManager的實(shí)現(xiàn)類(lèi)ProviderManager會(huì)將認(rèn)證委派給支持認(rèn)證該Authentication的AuthenticationProvider步藕。
  • 如果認(rèn)證失敗:
  • SecurityContextHolder被清空。
  • RememberMeServices.loginFail會(huì)被調(diào)用挑格,如果rememberme沒(méi)有被配置咙冗,將不會(huì)有任何操作。
  • AuthenticationFailureHandler被調(diào)用漂彤。
  • 如果認(rèn)證成功:

  • SessionAuthenticationStrategy會(huì)收到一個(gè)登錄通知雾消。
  • 這個(gè)Authencation會(huì)被放置到SecurityContextHolder中。
  • RememberMeServices.loginSuccess將被調(diào)用挫望,如果沒(méi)有設(shè)置rememberme立润,將不會(huì)有任何操作。
  • ApplicationEventPublisher發(fā)布一個(gè)InteractiveAuthenticationSuccessEvent媳板。


  • “ 自定義身份認(rèn)證

    在闡述完整個(gè)認(rèn)證架構(gòu)后桑腮,其實(shí)不難發(fā)現(xiàn),在自定義認(rèn)證的時(shí)候蛉幸,你需要做如下準(zhǔn)備:

    CustomAuthenticationToken


    CustomFilter

    ?CustomAuthenticationProvider


    你需要自定義一個(gè) AuthenticationProvider 的實(shí)現(xiàn)類(lèi)和一個(gè) Authentication 的實(shí)現(xiàn)類(lèi)破讨,還有一個(gè)繼承了AbstractAuthenticationProcessingFilter的過(guò)濾器。

    對(duì)于AuthenticationProvider 的實(shí)現(xiàn)類(lèi) CustomAuthenticationProvider奕纫,需要在authenticate方法中編寫(xiě)你自己的認(rèn)證算法提陶,并且通過(guò)實(shí)現(xiàn)supports方法告知調(diào)用者自己所支持認(rèn)證的Authentication類(lèi)型(在這里支持認(rèn)證的就是CustomAuthenticationToken類(lèi)型)。

    CustomAuthenticationToken是一個(gè)繼承了UsernamePasswordAuthenticationToken的子類(lèi)(UsernamePasswordAuthenticationToken是一個(gè)間接繼承了Authentication的類(lèi)匹层,它默認(rèn)實(shí)現(xiàn)了Authentication的所有接口隙笆,大多數(shù)情況下,你只需要繼承它就可以了又固,?當(dāng)然你也可以直接繼承Authentication),你可以從圖中看到它有兩個(gè)構(gòu)造函數(shù)煤率,這兩個(gè)構(gòu)造函數(shù)的使用時(shí)機(jī)是不同的仰冠,第一個(gè)構(gòu)造函數(shù)是通常由CustomFilter調(diào)用,然后將創(chuàng)建的CustomAuthenticationToken傳遞給AuthenticationManager進(jìn)行認(rèn)證(最終會(huì)由ProviderManager委托CustomAuthenticationProvider認(rèn)證)蝶糯,如果認(rèn)證成功洋只,CustomAuthenticationProvider會(huì)調(diào)用第二個(gè)構(gòu)造函數(shù)生成一個(gè)已認(rèn)證的CustomAuthenticationToken

    對(duì)于CustomFilter昼捍,它主要要做兩件事识虚,第一,在默認(rèn)構(gòu)造函數(shù)中通過(guò)調(diào)用父類(lèi)的setFilterProcessesUrl方法去配置需要攔截的url妒茬。第二担锤,它需要在attemptAuthentication中,把認(rèn)證相關(guān)的數(shù)據(jù)提取從HttpServletRequest中提取出來(lái)乍钻,然后調(diào)用CustomAuthenticationToken的第一個(gè)構(gòu)造函數(shù)創(chuàng)建CustomAuthenticationToken肛循,并將他傳遞給AuthenticationManager去認(rèn)證铭腕。


    最后,在完成了上述相關(guān)類(lèi)的實(shí)現(xiàn)了之后多糠,接下來(lái)我們只需要將它們按照下圖的代碼配置進(jìn)Spring Security即可累舷。


    SpringSecurity配置


    接下來(lái),這里有幾個(gè)小測(cè)驗(yàn)夹孔,可以幫助你了解你的掌握情況:

  • 你自定義的AuthenticationProvider需要實(shí)現(xiàn)哪兩個(gè)方法被盈,這兩個(gè)方法的用途是什么?

  • 你自定義的AuthenticationProvider如何配置到SpringSecurity中搭伤?

  • 你自定義的過(guò)濾器應(yīng)該要繼承哪一個(gè)類(lèi)只怎?這個(gè)過(guò)濾器有哪些職責(zé)?你自定義的過(guò)濾器如何添加到SpringSecurity的過(guò)濾器鏈中闷畸?

  • ?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
    • 序言:七十年代末尝盼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子佑菩,更是在濱河造成了極大的恐慌盾沫,老刑警劉巖,帶你破解...
      沈念sama閱讀 222,000評(píng)論 6 515
    • 序言:濱河連續(xù)發(fā)生了三起死亡事件殿漠,死亡現(xiàn)場(chǎng)離奇詭異赴精,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绞幌,發(fā)現(xiàn)死者居然都...
      沈念sama閱讀 94,745評(píng)論 3 399
    • 文/潘曉璐 我一進(jìn)店門(mén)蕾哟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人莲蜘,你說(shuō)我怎么就攤上這事谭确。” “怎么了票渠?”我有些...
      開(kāi)封第一講書(shū)人閱讀 168,561評(píng)論 0 360
    • 文/不壞的土叔 我叫張陵逐哈,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我问顷,道長(zhǎng)昂秃,這世上最難降的妖魔是什么? 我笑而不...
      開(kāi)封第一講書(shū)人閱讀 59,782評(píng)論 1 298
    • 正文 為了忘掉前任杜窄,我火速辦了婚禮肠骆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘塞耕。我一直安慰自己蚀腿,他們只是感情好,可當(dāng)我...
      茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
    • 文/花漫 我一把揭開(kāi)白布扫外。 她就那樣靜靜地躺著唯咬,像睡著了一般纱注。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胆胰,一...
      開(kāi)封第一講書(shū)人閱讀 52,394評(píng)論 1 310
    • 那天狞贱,我揣著相機(jī)與錄音,去河邊找鬼蜀涨。 笑死瞎嬉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厚柳。 我是一名探鬼主播氧枣,決...
      沈念sama閱讀 40,952評(píng)論 3 421
    • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼别垮!你這毒婦竟也來(lái)了便监?” 一聲冷哼從身側(cè)響起,我...
      開(kāi)封第一講書(shū)人閱讀 39,852評(píng)論 0 276
    • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤碳想,失蹤者是張志新(化名)和其女友劉穎烧董,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胧奔,經(jīng)...
      沈念sama閱讀 46,409評(píng)論 1 318
    • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逊移,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
      茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
    • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了龙填。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胳泉。...
      茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
    • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖岩遗,靈堂內(nèi)的尸體忽然破棺而出扇商,到底是詐尸還是另有隱情,我是刑警寧澤宿礁,帶...
      沈念sama閱讀 36,303評(píng)論 5 350
    • 正文 年R本政府宣布案铺,位于F島的核電站,受9級(jí)特大地震影響窘拯,放射性物質(zhì)發(fā)生泄漏红且。R本人自食惡果不足惜坝茎,卻給世界環(huán)境...
      茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
    • 文/蒙蒙 一涤姊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嗤放,春花似錦思喊、人聲如沸。這莊子的主人今日做“春日...
      開(kāi)封第一講書(shū)人閱讀 32,470評(píng)論 0 24
    • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)舆乔。三九已至,卻和暖如春剂公,著一層夾襖步出監(jiān)牢的瞬間希俩,已是汗流浹背。 一陣腳步聲響...
      開(kāi)封第一講書(shū)人閱讀 33,571評(píng)論 1 272
    • 我被黑心中介騙來(lái)泰國(guó)打工纲辽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颜武,地道東北人。 一個(gè)月前我還...
      沈念sama閱讀 49,041評(píng)論 3 377
    • 正文 我出身青樓拖吼,卻偏偏與公主長(zhǎng)得像鳞上,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吊档,可洞房花燭夜當(dāng)晚...
      茶點(diǎn)故事閱讀 45,630評(píng)論 2 359