WebSecurityConfigurerAdapter废弃后,Spring中获取AuthenticationManager实例及添加自定义Filter的问题求解
我完全理解你对Spring Security废弃WebSecurityConfigurerAdapter后的困惑——这玩意儿之前确实无处不在,新配置方式的文档又跟不上,搞个自定义Filter都要踩坑,太闹心了!
你遇到的核心问题其实是Bean的初始化时机:在SecurityFilterChain的Bean方法里直接调用http.getSharedObject(AuthenticationManager.class)时,Spring Security还没完成AuthenticationManager的创建和共享对象的注入,所以拿到null。而你那个自定义AbstractHttpConfigurer的方案能工作,是因为它的configure方法执行时机更晚,此时AuthenticationManager已经被初始化并存入了HttpSecurity的共享对象中。
下面给你几个简洁合理的解决方案:
方案1:直接调用http.getAuthenticationManager()
在SecurityFilterChain配置方法里,用http.getAuthenticationManager()替代getSharedObject,这个方法会自动触发AuthenticationManager的构建流程,确保拿到的是有效实例:
@Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ AuthenticationManager authenticationManager = http.getAuthenticationManager(); AuthFilter filter = new AuthFilter(); filter.setAuthenticationManager(authenticationManager); // 记得把自定义Filter加到合适的位置,比如放在用户名密码认证Filter之前 http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); // 其他安全配置... return http.build(); }
方案2:将AuthenticationManager暴露为独立Bean
如果需要在多个地方复用AuthenticationManager,可以直接把它注册为Bean,之后在需要的地方注入即可:
@Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } // 在SecurityFilterChain中注入使用 @Bean SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception{ AuthFilter filter = new AuthFilter(); filter.setAuthenticationManager(authenticationManager); http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); // 其他安全配置... return http.build(); }
这是Spring Security官方推荐的暴露AuthenticationManager的方式,通过AuthenticationConfiguration能确保拿到的是完全初始化后的实例。
方案3:保留自定义AbstractHttpConfigurer(并非多余)
你觉得“多余”的那个结构其实是官方推荐的模块化配置扩展方式,它的优势在于可以把相关的自定义配置封装起来,方便复用。如果你的配置逻辑比较复杂,这种方式反而会让代码更清晰。而且它确实能保证在正确的时机获取AuthenticationManager,因为AbstractHttpConfigurer的configure方法是在HttpSecurity核心配置完成后才执行的。
为什么authenticationManagerBuilder.build()会报错?
当你尝试直接调用authenticationManagerBuilder.build()时,Spring Security在内部配置流程中已经完成了AuthenticationManagerBuilder的构建,所以手动调用会触发“already built”错误;而如果此时尝试获取实例返回null,是因为构建流程还没走到那一步;getOrBuild()同样会报错,因为它不允许重复构建。所以不建议直接操作AuthenticationManagerBuilder,改用上面的方案更稳妥。
内容的提问来源于stack exchange,提问作者Tim

