基本原理
Spring Security都使用了設(shè)計(jì)模式中的責(zé)任鏈模式,它們都定義了許多過(guò)濾器(Filter),每一個(gè)請(qǐng)求都會(huì)經(jīng)過(guò)層層過(guò)濾器的處理。

其中,Spring Security 在 Servlet 的過(guò)濾鏈(filter chain)中注冊(cè)了一個(gè)過(guò)濾器 FilterChainProxy,它會(huì)把請(qǐng)求代理到 Spring Security 自己維護(hù)的多個(gè)過(guò)濾鏈,每個(gè)過(guò)濾鏈會(huì)匹配一些 URL,如圖中的 /foo/**,如果匹配則執(zhí)行對(duì)應(yīng)的過(guò)濾器。過(guò)濾鏈?zhǔn)怯许樞虻模粋€(gè)請(qǐng)求只會(huì)執(zhí)行第一條匹配的過(guò)濾鏈。
Spring Security 的配置本質(zhì)上就是新增、刪除、修改過(guò)濾器
為便于使用,Spring Security默認(rèn)實(shí)現(xiàn)了很多的過(guò)濾器,如 UsernamePasswordAuthenticationFilter 來(lái)處理用戶名密碼的認(rèn)證, SessionManagementFilter 來(lái)管理 Session 等等。
下面以 UsernamePasswordAuthenticationFilter 為例來(lái)講講Spring Security的認(rèn)證過(guò)程。其實(shí)也簡(jiǎn)單,就兩步:
-
UsernamePasswordAuthenticationFilter攔截器匹配/login的POST請(qǐng)求,保存認(rèn)證信息(用戶名和密碼) - 最終由用戶實(shí)現(xiàn)
UsernamePasswordAuthenticationProvider(authenticate方法) 進(jìn)行實(shí)際認(rèn)證
代碼邏輯
代碼比較清晰,主要關(guān)注幾點(diǎn):
- 由
UsernamePasswordAuthenticationFilter定義了過(guò)濾器需要匹配的url -
UsernamePasswordAuthenticationFilter的父類AbstractAuthenticationProcessingFilter定義doFilter方法實(shí)現(xiàn)整個(gè)認(rèn)證流程,該過(guò)程調(diào)用attemtAuthentication進(jìn)行認(rèn)證,保存認(rèn)證結(jié)果并根據(jù)結(jié)果調(diào)用successfulAuthentication或者unsuccessfulAuthentication。 -
attemtAuthentication方法最終會(huì)由用戶實(shí)現(xiàn)的UsernamePasswordAuthenticationProvider(authenticate方法) 進(jìn)行實(shí)際認(rèn)證
UsernamePasswordAuthenticationFilter定義過(guò)濾器需要匹配的url(/login的POST請(qǐng)求)
UsernamePasswordAuthenticationFilter繼承AbstractAuthenticationProcessingFilter用于處理/login的POST請(qǐng)求

AbstractAuthenticationProcessingFilter定義doFilter方法實(shí)現(xiàn)整個(gè)認(rèn)證流程
在AbstractAuthenticationProcessingFilter的doFilter方法中會(huì)調(diào)用attemptAuthentication方法,該方法進(jìn)行認(rèn)證生成認(rèn)證結(jié)果,最終認(rèn)證結(jié)果由session處理。

UsernamePasswordAuthenticationProvider(authenticate方法) 進(jìn)行實(shí)際認(rèn)證
UsernamePasswordAuthenticationFilter執(zhí)行認(rèn)證
UsernamePasswordAuthenticationFilter會(huì)實(shí)現(xiàn)父類中的attemptAuthentication方法,該方法首先生成UsernamePasswordAuthenticationToken保存認(rèn)證信息。然后調(diào)用AuthenticationManager的authenticate方法認(rèn)證。

注意: 不同的filter會(huì)將認(rèn)證信息保存到不同類型的結(jié)果中, 后續(xù)Spring Security會(huì)根據(jù)認(rèn)證信息類型尋找合適的
AuthenticationProvider進(jìn)行認(rèn)證,UsernamePasswordAuthenticationFilter將結(jié)果保存到UsernamePasswordAuthenticationToken中。
AuthenticationManager調(diào)用各AuthenticationProvider執(zhí)行認(rèn)證
ProviderManager實(shí)現(xiàn)AuthenticationManager接口, ProviderManager首先通過(guò)AuthenticationProvider中的support方法找到合適的AuthenticationProvider,然后調(diào)用authenticate認(rèn)證方法

對(duì)于UsernamePasswordAuthenticationFilter,通常我們需要實(shí)現(xiàn)自己的UsernamePasswordAuthenticationProvider(實(shí)現(xiàn)AuthenticationProvider接口)用于用戶名和密碼驗(yàn)證以及加入一些需要的用戶信息如角色、權(quán)限等到認(rèn)證結(jié)果中。
示例:

源碼
https://gitee.com/awesome-engineer/spring-cloud-family-bucket