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