Java中的Spring Security配置過濾器
前言:
CaptchaAuthenticationFilter
是通過模仿UsernamePasswordAuthenticationFilter
實現(xiàn)的。同樣的道理,由于UsernamePasswordAuthenticationFilter
的配置是由FormLoginConfigurer
來完成的,應該也能模仿一下FormLoginConfigurer
,寫一個配置類CaptchaAuthenticationFilterConfigurer
去配置CaptchaAuthenticationFilter
。
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> { // 省略 }
AbstractAuthenticationFilterConfigurer
FormLoginConfigurer
看起來有點復雜,不過繼承關系并不復雜,只繼承了AbstractAuthenticationFilterConfigurer
。
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter> extends AbstractHttpConfigurer<T, B> { }
理論上我們模仿一下,也繼承一下這個類,但是你會發(fā)現(xiàn)這種方式行不通。因為AbstractAuthenticationFilterConfigurer
只能Spring Security內(nèi)部使用,不建議自定義。原因在于它最終向HttpSecurity
添加過濾器使用的是HttpSecurity.addFilter(Filter)
方法,這個方法只有內(nèi)置過濾器(參見FilterOrderRegistration
)才能使用。了解了這個機制之后,我們只能往上再抽象一層,去改造其父類AbstractHttpConfigurer
。
改造過程
AbstractAuthenticationFilterConfigurer<B,T,F>
中的B
是實際指的HttpSecurity
,因此這個要保留;
T
指的是它本身的實現(xiàn),我們配置CaptchaAuthenticationFilter
不需要下沉一層到FormLoginConfigurer
這個繼承級別,直接在AbstractAuthenticationFilterConfigurer
這個繼承級別實現(xiàn)即可,因此T
這里指的就是需要配置類本身,也不需要再抽象化,因此是不需要的;同樣的原因F
也不需要,很明確是CaptchaAuthenticationFilter
,不需要再泛化。這樣CaptchaAuthenticationFilter
的配置類結構可以這樣定義:
public class CaptchaAuthenticationFilterConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<CaptchaAuthenticationFilterConfigurer<H>, H> { // 不再泛化 具體化 private final CaptchaAuthenticationFilter authFilter; // 特定的驗證碼用戶服務 private CaptchaUserDetailsService captchaUserDetailsService; // 驗證碼處理服務 private CaptchaService captchaService; // 保存認證請求細節(jié)的策略 private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource; // 默認使用保存請求認證成功處理器 private SavedRequestAwareAuthenticationSuccessHandler defaultSuccessHandler = new SavedRequestAwareAuthenticationSuccessHandler(); // 認證成功處理器 private AuthenticationSuccessHandler successHandler = this.defaultSuccessHandler; // 登錄認證端點 private LoginUrlAuthenticationEntryPoint authenticationEntryPoint; // 是否 自定義頁面 private boolean customLoginPage; // 登錄頁面 private String loginPage; // 登錄成功url private String loginProcessingUrl; // 認證失敗處理器 private AuthenticationFailureHandler failureHandler; // 認證路徑是否放開 private boolean permitAll; // 認證失敗的url private String failureUrl; /** * Creates a new instance with minimal defaults */ public CaptchaAuthenticationFilterConfigurer() { setLoginPage("/login/captcha"); this.authFilter = new CaptchaAuthenticationFilter(); } public CaptchaAuthenticationFilterConfigurer<H> formLoginDisabled() { this.formLoginEnabled = false; return this; } public CaptchaAuthenticationFilterConfigurer<H> captchaUserDetailsService(CaptchaUserDetailsService captchaUserDetailsService) { this.captchaUserDetailsService = captchaUserDetailsService; return this; } public CaptchaAuthenticationFilterConfigurer<H> captchaService(CaptchaService captchaService) { this.captchaService = captchaService; return this; } public CaptchaAuthenticationFilterConfigurer<H> usernameParameter(String usernameParameter) { authFilter.setUsernameParameter(usernameParameter); return this; } public CaptchaAuthenticationFilterConfigurer<H> captchaParameter(String captchaParameter) { authFilter.setCaptchaParameter(captchaParameter); return this; } public CaptchaAuthenticationFilterConfigurer<H> parametersConverter(Converter<HttpServletRequest, CaptchaAuthenticationToken> converter) { authFilter.setConverter(converter); return this; } @Override public void init(H http) throws Exception { updateAuthenticationDefaults(); updateAccessDefaults(http); registerDefaultAuthenticationEntryPoint(http); // 這里禁用默認頁面過濾器 如果你想自定義登錄頁面 可以自行實現(xiàn) 可能和FormLogin沖突 // initDefaultLoginFilter(http); // 把對應的Provider也在init時寫入HttpSecurity initProvider(http); } @Override public void configure(H http) throws Exception { //這里改為使用前插過濾器方法 http.addFilterBefore(filter, LogoutFilter.class); } // 其它方法 同AbstractAuthenticationFilterConfigurer }
其實就是模仿AbstractAuthenticationFilterConfigurer
及其實現(xiàn)類的風格把用的配置項實現(xiàn)一邊。這里值得一提的是CaptchaService
的配置也可以從Spring IoC中查找(參考getBeanOrNull
方法,這個方法在Spring Security中隨處可見,建議借鑒),這樣更加靈活,既能從方法配置也能自動注入。
private void initProvider(H http) { ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class); // 沒有配置CaptchaUserDetailsService就去Spring IoC獲取 if (captchaUserDetailsService == null) { captchaUserDetailsService = getBeanOrNull(applicationContext, CaptchaUserDetailsService.class); } // 沒有配置CaptchaService就去Spring IoC獲取 if (captchaService == null) { captchaService = getBeanOrNull(applicationContext, CaptchaService.class); } // 初始化 Provider CaptchaAuthenticationProvider captchaAuthenticationProvider = this.postProcess(new CaptchaAuthenticationProvider(captchaUserDetailsService, captchaService)); // 會增加到ProviderManager的注冊列表中 http.authenticationProvider(captchaAuthenticationProvider); }
配置類效果
我們來看看CaptchaAuthenticationFilterConfigurer
的配置效果:
@Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, UserDetailsService userDetailsService) throws Exception { http.csrf().disable() .authorizeRequests() .mvcMatchers("/foo/**").access("hasAuthority('ROLE_USER')") .anyRequest().authenticated() .and() // 所有的 AbstractHttpConfigurer 都可以通過apply方法加入HttpSecurity .apply(new CaptchaAuthenticationFilterConfigurer<>()) // 配置驗證碼處理服務 這里直接true 方便測試 .captchaService((phone, rawCode) -> true) // 通過手機號去拿驗證碼,這里為了方便直接寫死了,實際phone和username做個映射 .captchaUserDetailsService(phone -> userDetailsService.loadUserByUsername("felord")) // 默認認證成功跳轉到/路徑 這里改造成把認證信息直接返回json .successHandler((request, response, authentication) -> { // 這里把認證信息以JSON形式返回 ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response); MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); mappingJackson2HttpMessageConverter.write(authentication, MediaType.APPLICATION_JSON,servletServerHttpResponse); }); return http.build(); }
是不是要優(yōu)雅很多,解決了你自己配置過濾器的很多疑難雜癥。學習一定要模仿,先模仿成功,然后再分析思考為什么會模仿成功,最后形成自己的創(chuàng)造力。千萬不要被一些陌生概念唬住,有些改造是不需要去深入了解細節(jié)的。
到此這篇關于Java中的Spring Security配置濾器的文章就介紹到這了,更多相關Spring Security過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解java WebSocket的實現(xiàn)以及Spring WebSocket
這篇文章主要介紹了詳解java WebSocket的實現(xiàn)以及Spring WebSocket ,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-01-01java中BeanUtils.copyProperties的用法(超詳細)
本文介紹了BeanUtils.copyProperties()方法的使用,包括其功能、用法、注意事項和示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-08-08