自定義SpringSecurity認證方式

就理論而言,理論和實踐并無差異,但真付諸實行,差異即開始顯現(xiàn)。


Jan?L.A van de Snepscheut


我們在軟件開發(fā)過程中,需要針對不同的軟件產(chǎn)品需求,提供不同的身份認證方式,縱使SpringSecurity非常強大,她所提供的身份認證方式也不足以面對各式各樣的身份認證方式,所以學習如何擴展SpringSecurity的認證方式也就非常有必要了。


注意!這不是一篇對于SpringSecurity毫無了解的讀者準備的,所以在閱讀這篇文章之前你需要了解對SpringSecurity有一些基礎的了解。


“ Spring Security的認證流程

在我們自定義SpringSecurity的認證方式之前,先從SpringSecurity的用戶名/密碼認證中了解SpringSecurity的認證流程,以及參與到這個流程的類它們各自的職責是什么。

用戶名/密碼認證流程(SecurityFilterChain中每一個橙色矩形條代表一個SecurityFilter,因為這里主要講解用戶名/密碼認證,故突出顯示UsernamePasswordAuthenticationFilter)


  • 當用戶提交他們的用戶名和密碼時,這個UsernamePasswordAuthenticationFilter會從HttpServletRequest提取用戶名和密碼,然后使用提取出的用戶名和密碼創(chuàng)建UsernamePasswordAuthenticationToken。

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

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

  • DaoAuthenticationProvider會通過UserDetailsService類使用UsernamePasswordAuthenticationToken中username去查詢用戶,然后對該用戶進行身份認證。

  • 如果認證失?。?/p>

  • SecurityContextHolder被清空。

  • RememberMeServices.loginFail會被調(diào)用,如果rememberme沒有被配置,將不會有任何操作。

  • AuthenticationFailureHandler被調(diào)用。

  • 如果認證成功:

  • SessionAuthenticationStrategy會收到一個登錄通知。

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

  • 如果沒有設置rememberme,將不會有任何操作。

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


  • 從上述的用戶名/密碼認證的流程中,我們可以得出如下圖所示的一個通用流程。

    抽象認證流程

  • 當用戶提交他們的憑證的時候,AbstractAuthenticationProcessingFilter會從HttpServletRequest提取相關的數(shù)據(jù)創(chuàng)建一個Authentication去認證。這個被創(chuàng)建的Authentication的類型取決于AbstractAuthenticationProcessingFilter的子類(例如,UsernamePasswordAuthenticationFilter就是從被提交的HttpServletRequest中提取出用戶名和密碼,然后創(chuàng)建了UsernamePasswordAuthenticationToken)。
  • 接下來,這個Authentication被傳入AuthenticationManager去認證,然后AuthenticationManager的實現(xiàn)類ProviderManager會將認證委派給支持認證該Authentication的AuthenticationProvider。
  • 如果認證失敗:
  • SecurityContextHolder被清空。
  • RememberMeServices.loginFail會被調(diào)用,如果rememberme沒有被配置,將不會有任何操作。
  • AuthenticationFailureHandler被調(diào)用。
  • 如果認證成功:

  • SessionAuthenticationStrategy會收到一個登錄通知。
  • 這個Authencation會被放置到SecurityContextHolder中。
  • RememberMeServices.loginSuccess將被調(diào)用,如果沒有設置rememberme,將不會有任何操作。
  • ApplicationEventPublisher發(fā)布一個InteractiveAuthenticationSuccessEvent。


  • “ 自定義身份認證

    在闡述完整個認證架構后,其實不難發(fā)現(xiàn),在自定義認證的時候,你需要做如下準備:

    CustomAuthenticationToken


    CustomFilter

    ?CustomAuthenticationProvider


    你需要自定義一個 AuthenticationProvider 的實現(xiàn)類和一個 Authentication 的實現(xiàn)類,還有一個繼承了AbstractAuthenticationProcessingFilter的過濾器。

    對于AuthenticationProvider 的實現(xiàn)類 CustomAuthenticationProvider,需要在authenticate方法中編寫你自己的認證算法,并且通過實現(xiàn)supports方法告知調(diào)用者自己所支持認證的Authentication類型(在這里支持認證的就是CustomAuthenticationToken類型)。

    CustomAuthenticationToken是一個繼承了UsernamePasswordAuthenticationToken的子類(UsernamePasswordAuthenticationToken是一個間接繼承了Authentication的類,它默認實現(xiàn)了Authentication的所有接口,大多數(shù)情況下,你只需要繼承它就可以了,?當然你也可以直接繼承Authentication),你可以從圖中看到它有兩個構造函數(shù),這兩個構造函數(shù)的使用時機是不同的,第一個構造函數(shù)是通常由CustomFilter調(diào)用,然后將創(chuàng)建的CustomAuthenticationToken傳遞給AuthenticationManager進行認證(最終會由ProviderManager委托CustomAuthenticationProvider認證),如果認證成功,CustomAuthenticationProvider會調(diào)用第二個構造函數(shù)生成一個已認證的CustomAuthenticationToken

    對于CustomFilter,它主要要做兩件事,第一,在默認構造函數(shù)中通過調(diào)用父類的setFilterProcessesUrl方法去配置需要攔截的url。第二,它需要在attemptAuthentication中,把認證相關的數(shù)據(jù)提取從HttpServletRequest中提取出來,然后調(diào)用CustomAuthenticationToken的第一個構造函數(shù)創(chuàng)建CustomAuthenticationToken,并將他傳遞給AuthenticationManager去認證。


    最后,在完成了上述相關類的實現(xiàn)了之后,接下來我們只需要將它們按照下圖的代碼配置進Spring Security即可。


    SpringSecurity配置


    接下來,這里有幾個小測驗,可以幫助你了解你的掌握情況:

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

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

  • 你自定義的過濾器應該要繼承哪一個類?這個過濾器有哪些職責?你自定義的過濾器如何添加到SpringSecurity的過濾器鏈中?

  • ?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
    【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
    平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

    友情鏈接更多精彩內(nèi)容