您现在的位置是:亿华云 > 应用开发

绝活!Spring Security过滤器就该这么配置

亿华云2025-10-04 03:18:31【应用开发】1人已围观

简介以前胖哥带大家用Spring Security过滤器实现了手机验证码认证,今天我们来改良一下验证码认证的配置方式。这绝对是绝活666,不再看、点赞一波吗?天天白嫖,晚上睡得着觉?

以前胖哥带大家用Spring Security过滤器实现了手机验证码认证,绝活今天我们来改良一下验证码认证的过滤配置方式。这绝对是器该绝活666,不再看、配置点赞一波吗?绝活天天白嫖,晚上睡得着觉?过滤

CaptchaAuthenticationFilter这个验证码过滤器是通过模仿UsernamePasswordAuthenticationFilter实现的。同样的器该道理,由于UsernamePasswordAuthenticationFilter的配置配置是由FormLoginConfigurer来完成的,应该也能模仿一下FormLoginConfigurer,绝活写一个配置类CaptchaAuthenticationFilterConfigurer去配置CaptchaAuthenticationFilter。过滤

public final class FormLoginConfigurer> extends

AbstractAuthenticationFilterConfigurer, UsernamePasswordAuthenticationFilter> {

// 省略

}

AbstractAuthenticationFilterConfigurer

FormLoginConfigurer看起来有点复杂,不过继承关系并不复杂,配置只继承了AbstractAuthenticationFilterConfigurer。绝活

public abstract class AbstractAuthenticationFilterConfigurer,过滤 T extends AbstractAuthenticationFilterConfigurer, F extends AbstractAuthenticationProcessingFilter>

extends AbstractHttpConfigurer{

}

理论上我们模仿一下,也继承一下这个类,器该但是你会发现这种方式行不通。因为AbstractAuthenticationFilterConfigurer只能Spring Security内部使用,不建议自定义。原因在于它最终向HttpSecurity添加过滤器使用的是HttpSecurity.addFilter(Filter)方法,这个方法只有内置过滤器(参见FilterOrderRegistration)才能使用。了解了这个机制之后,我们只能往上再抽象一层,亿华云计算去改造其父类AbstractHttpConfigurer。

改造过程

AbstractAuthenticationFilterConfigurer中的B是实际指的HttpSecurity,因此这个要保留;

T指的是它本身的实现,我们配置CaptchaAuthenticationFilter不需要下沉一层到FormLoginConfigurer这个继承级别,直接在AbstractAuthenticationFilterConfigurer这个继承级别实现即可,因此T这里指的就是需要配置类本身,也不需要再抽象化,因此是不需要的;同样的原因F也不需要,很明确是CaptchaAuthenticationFilter,不需要再泛化。这样CaptchaAuthenticationFilter的配置类结构可以这样定义:

public class CaptchaAuthenticationFilterConfigurer> extends AbstractHttpConfigurer, H> {

// 不再泛化 具体化

private final CaptchaAuthenticationFilter authFilter;

// 特定的验证码用户服务

private CaptchaUserDetailsService captchaUserDetailsService;

// 验证码处理服务

private CaptchaService captchaService;

// 保存认证请求细节的策略

private AuthenticationDetailsSourceauthenticationDetailsSource;

// 默认使用保存请求认证成功处理器

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 CaptchaAuthenticationFilterConfigurerformLoginDisabled() {

this.formLoginEnabled = false;

return this;

}

public CaptchaAuthenticationFilterConfigurercaptchaUserDetailsService(CaptchaUserDetailsService captchaUserDetailsService) {

this.captchaUserDetailsService = captchaUserDetailsService;

return this;

}

public CaptchaAuthenticationFilterConfigurercaptchaService(CaptchaService captchaService) {

this.captchaService = captchaService;

return this;

}

public CaptchaAuthenticationFilterConfigurerusernameParameter(String usernameParameter) {

authFilter.setUsernameParameter(usernameParameter);

return this;

}

public CaptchaAuthenticationFilterConfigurercaptchaParameter(String captchaParameter) {

authFilter.setCaptchaParameter(captchaParameter);

return this;

}

public CaptchaAuthenticationFilterConfigurerparametersConverter(Converterconverter) {

authFilter.setConverter(converter);

return this;

}

@Override

public void init(H http) throws Exception {

updateAuthenticationDefaults();

updateAccessDefaults(http);

registerDefaultAuthenticationEntryPoint(http);

// 这里禁用默认页面过滤器 如果你想自定义登录页面 可以自行实现 可能和FormLogin冲突

// initDefaultLoginFilter(http);

// 把对应的Provider也在init时写入HttpSecurity

initProvider(http);

}

@Override

public void configure(H http) throws Exception {

//这里改为使用前插过滤器方法

http.addFilterBefore(filter, LogoutFilter.class);

}

// 其它方法 同AbstractAuthenticationFilterConfigurer

}

其实就是模仿AbstractAuthenticationFilterConfigurer及其实现类的风格把用的站群服务器配置项实现一遍。这里值得一提的是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();

}

是不是要优雅很多,解决了你自己配置过滤器的很多疑难杂症。学习一定要模仿,先模仿成功,然后再分析思考为什么会模仿成功,最后形成自己的创造力。千万不要被一些陌生概念唬住,有些改造是不需要去深入了解细节的。

本文转载自微信公众号「码农小胖哥」,可以通过以下二维码关注。转载本文请联系码农小胖哥公众号。

亿华云

很赞哦!(858)