Spring Security Architecture

Yovan
5 min readApr 28, 2018

--

Spring Security 在 Web 上,是透過一系列的 Servlet Filter 來管理, 在 Spring Security 中已經定義了一些 Filter , 每個 Filter 各代表著不同功能 , Filter 彼此之間有著一定的關聯順序,所以他們是有固定的執行順序。

Spring Security Filter Chain

Spring Framework 透過 GenericFilterBean 提供 Filter 在初始化時,可以從設定中取得設定值

在 Filter Chain 中,UsernamePasswordAuthenticationFilter 是一個很重要的Filter,提供一個取得認證的方法,保護 Server Service ,只能在有認證過情況下, 才能進一步 access。

Spring Security 在認證方面可以分為兩個部分Authentication 和 Authorization

  • Authentication: 確認這個人是誰 ( Who the person )
  • Authorization: 可以允許這個人做什麼 ( Allow the person to do what)

一般來說,Authentication 通常會伴隨著 Authorization!

例如,一個 User進入某的網站, login 之後 ( Authentication ),可以看到會員專屬內容,表示此 User有這樣的會員權限 ( Authorization )。

我們看一下Spring Security 認證部分的架構

架構大致上分為 六 個部分

1. AuthenticationManager :

  • 負責認證,但又不直接做認證工作,而是委託 AuthenitcationProvider list去做認證,如果其中一個 AuthenitcationProvider 認證成功, 就不會繼續認證下去。

2. AuthenitcationProvider:

  • 真正實踐認證工作

3. UserDetailsService:

  • 單純取得 User 資訊,不做認證工作!
  • User 資訊來源可能是從 DB、Memory 或第三方帳號管理系統,而衍生不同的實作。

4. UserDetails:

  • 封裝 User 資訊

5. Authentication:

  • 表示一個 User 的認證訊息

6. SecuritycContextHolder:

  • 用來保存 SecurityContext, 而SecurityContext 保存當前的 User 認證訊息 ( Authentication )。
  • SecuritycContextHolder 預設採用 ThreadLocal 保存 SecurityContext,也就是說,可以從 ThreadLocal 取得當前的 SecurityContext。

我們知道 Servlet 3.0 之前,每個 request 都會透過一個獨立的 thread 來處理 !

所以 SecuritycContextHolder 在收到一個 reuqest 的時候都會透過 ThreadLocal 放進 與此 User 相關的 SecurityContext,在 reuqest 結束後,又把它清空。

Spring Security Authentication Flow

User Login Authentication Flow

當一個認證的 Request 進來 ( uri 預設通常是 /login ),在 Spring Security 流程中 , 會經過 Filter Chain 中的 UsernamePasswordAuthenticationFilter ( 這裡會判斷是不是 /login,才決定要不要走這個 Filter 的程序 或 繼續執行下一個Filter )。

refer to Spring Security 4.2.3 source code

Filter Chain 中的 UsernamePasswordAuthenticationFilter 繼承了一個 AbstractAuthenticationProcessingFilter,它實作了 Servlet Filter 的 doFilter,並讓繼承它的 class 能更專注在 authenticate ( 實作 attemptAuthentication method )。從 UsernamePasswordAuthenticationFilter 中可以看到,它會先產生一個 UsernamePasswordAuthenticationToken ( Authentication實作 ),接著交給 AuthenticationManager 處理認證,如果回傳一個 Authentiation 就是認證成功,反之失敗。 最後 AbstractAuthenticationProcessingFilter 會依照回傳結果,做不同的處理。

Per Request Flow after User Authenticated

當一個 Request 進來,最後都會走到 FilterSecurityInterceptor Filter 來,只要Requst 取的 uri 是受保護的資源,會從SecurityContextHolder 取得這 User 的Authentication,判斷是否已經認證過,決定能不能 access。

--

--

Yovan

時間不會為誰而停留,就算暫停了全世界的鐘,也停不了這一秒鐘,所以有什麼理由,不好好把握每一刻! 希望現在開始透過紀錄,留下在軟體開發的路途上,每個走過的足跡! www.linkedin.com/in/yovan-li