繼承 AbstractProcessingFilter,doFilter() 攔截 HTTP 請求,判斷 requiresAuthentication()(預設匹配登入 URL)。需認證時呼叫 attemptAuthentication():
obtainUsername/password()。UsernamePasswordAuthenticationToken(未認證的 Authentication 實作)。AuthenticationManager.authenticate() 執行認證。成功呼叫 successfulAuthentication()(通常重導向),失敗呼叫 unsuccessfulAuthentication()。
AbstractAuthenticationManager.authenticate() 模板方法呼叫 doAuthentication()。ProviderManager 維護 AuthenticationProvider 鏈:
supports() 檢查支援的 Authentication 類型。provider.authenticate(),成功發布 AuthenticationSuccessEvent 並返回;失敗記錄異常繼續下一 Provider。ProviderNotFoundException 或最後異常。繼承 AbstractUserDetailsAuthenticationProvider,流程:
UserCache) 獲取 UserDetails。retrieveUser() → 委派 UserDetailsService.loadUserByUsername() 從資料庫載入。additionalAuthenticationChecks() 比對密碼(支援 PasswordEncoder 加鹽雜湊)。UserDetails 存入快取,建構含權限的 Authentication 返回。預設 SQL:
SELECT username,password,enabled FROM users WHERE username = ?
SELECT username,authority FROM authorities WHERE username = ?
使用 Spring MappingSqlQuery 將 ResultSet 映射為 GrantedAuthority 與 User 物件。loadUserByUsername() 合併查詢結果構建完整 UserDetails。
protected void additionalAuthenticationChecks(UserDetails user, UsernamePasswordAuthenticationToken auth) {
String presented = auth.getCredentials().toString();
if (!passwordEncoder.isPasswordValid(user.getPassword(), presented, salt))
throw new BadCredentialsException(...);
}
支援 SaltSource 取得鹽值,PasswordEncoder 驗證雜湊密碼。
認證流程:AuthenticationProcessingFilter 攔截 → 建構 Token → ProviderManager 遍歷 Provider → DaoAuthenticationProvider 透過 UserDetailsService (如 JdbcDaoImpl) 載入使用者資料 → 狀態檢查 → 密碼編碼比對 → 產出含權限的 Authentication 供後續授權使用。架構靈活支援多種認證來源與編碼策略。