// 先將JwtFilter印入
private final JwtAuthenticationFilter jwtAuthenticationFilter;
// 並加進初始化中
public SecurityConfiguration(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception{
httpSecurity
// ...省略
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
DelegatingFilterProxy,它可以將請求轉接到Spring的FilterChain中。DelegatingFilterProxy 就是將原本Servlet的Filter邏輯委派給Spring Bean(SecurityFilter)來代理!FilterChainProxy,這時請求就正式進入了Spring FilterChain的領域啦~HTTP Request → DelegatingFilterProxy → FilterChainProxy → Controller
FilterChainProxy 本身!
List<SecurityFilterChain>,並針對不同URL使用不同的FilterChain。SecurityContextHolderFilter,載入上下文,掌管FilterChain的開始與結束。
SecurityContextRepository 載入之前的資訊,像是Session,並放入ThreadLocal。CorsFilter、CsrfFilter、HeaderWriterFilter、LogoutFilter,這邊就不多贅述,直接進入到重點。AuthenticationFilter ➝ 「決定你是誰」
.formLogin() 的登入功能,去攔截 [POST] /login,並取得username、password,委派給AuthenticationManager。這樣的功能是寫在 UsernamePasswordAuthenticationFilter 中,這是STATEFUL的部分,也就是身分存儲於Session中。.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);,我將設置Context的動作交由Jwt實施,而由於沒有在配置檔中啟用 formLogin,因此UsernamePasswordAuthenticationFilter根本就不會被放進FilterChain中!AuthorizationFilter ➝ 「決定你這個身分能去哪」
permitAll、authenticated 都是在這層認證Filter中去做動作,以下是簡略圖 : Request 到達 AuthorizationFilter
│
▼
拿URL去比對你在 SecurityConfig 寫的規則
│
┌─────────────────────┴───────────────────────┐
▼ ▼
命中 permitAll() 規則 命中 .authenticated() 規則
│ │
【直接放行!】 檢查 SecurityContextHolder
│ 有沒有已認證的 Authentication?
│ │
│ ┌─────────────┴─────────────┐
│ ▼ ▼
│ 【有(已登入)】 【未登入/Token無效】
│ │ │
│ 【放行通過!】 【拋出 403 / 401】
│ │ │
└─────────────────┬─────────────┘ │
▼ ▼
順利進入 Controller 中斷請求,返回錯誤
PreAuthorize 等AOP機制!本篇文章出自《每天學Java直到今年結束》Day232,大家可以到我的網站上查看~