【BUG记录】SpringSecurity6.2以上 AuthenticationManager=null

个人博客接入ai大模型
部分堆栈信息
java.lang.NullPointerException: Cannot invoke "org.springframework.security.authentication.AuthenticationManager.authenticate(org.springframework.security.core.Authentication)" because the return value of "com.eleventh.oneblog.jwt.filter.JwtAuthenticationFilter.getAuthenticationManager()" is null
参考文章: Spring Security authenticationManager()返回null,必须定义authenticationManagerBean的原因分析

该错误的根本原因还是在于显式设置 AuthenticationManager 到 HttpSecurity。

参考其他文章并没有指出具体设置位置。在多模块开发下,我的springSecurity的执行链为WebSecurityConfig->TokenAuthenticationFilter->jwtAuthenticationSecurityConfig->JwtAuthenticationFilter。而最开始我将AuthenticationManager显式设置在WebSecurityConfig但执行结果同样报错

 @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
    
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    // 显式获取并设置 AuthenticationManager
    AuthenticationManager authManager = authenticationManager(http.getSharedObject(AuthenticationConfiguration.class));
    http.authenticationManager(authManager);

    // 先配置其他安全设置
    http
        .csrf(AbstractHttpConfigurer::disable)
        .formLogin(AbstractHttpConfigurer::disable)
        .httpBasic(basic -> basic.authenticationEntryPoint(authEntryPoint))
        .exceptionHandling(exception -> exception.accessDeniedHandler(deniedHandler))
        .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/admin/**").authenticated()
            .anyRequest().permitAll()
        )
        .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

    // 最后配置 JWT 安全模块
    jwtAuthenticationSecurityConfig.configure(http);
    
    return http.build();
}


原因是咋多模块开发下,将jwt安全认证与springSecurity分开在不同模块,同时关键类SecurityConfigurerAdapter并没有在WebSecurityConfig继承。SecurityConfigurerAdapter继承在jwtAuthenticationSecurityConfig中,所以AuthenticationManager显式设置也应该在该配置类中


@Configuration
public class JwtAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    @Autowired
    private RestAuthenticationSuccessHandler restAuthenticationSuccessHandler;

    @Autowired
    private RestAuthenticationFailureHandler restAuthenticationFailureHandler;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {

        // 先设置 AuthenticationManager
        AuthenticationManager authManager = authenticationManager(
                httpSecurity.getSharedObject(AuthenticationConfiguration.class)
        );
//        httpSecurity.authenticationManager(authManager);

        // 自定义的用于 JWT 身份验证的过滤器
        JwtAuthenticationFilter filter = new JwtAuthenticationFilter();
        filter.setAuthenticationManager(authManager);

        // 设置登录认证对应的处理类(成功处理、失败处理)
        filter.setAuthenticationSuccessHandler(restAuthenticationSuccessHandler);
        filter.setAuthenticationFailureHandler(restAuthenticationFailureHandler);

        // 直接使用 DaoAuthenticationProvider, 它是 Spring Security 提供的默认的身份验证提供者之一
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 设置 userDetailService,用于获取用户的详细信息
        provider.setUserDetailsService(userDetailsService);
        // 设置加密算法
        provider.setPasswordEncoder(passwordEncoder);
        httpSecurity.authenticationProvider(provider);
        // 将这个过滤器添加到 UsernamePasswordAuthenticationFilter 之前执行
        httpSecurity.addFilterAfter(filter, UsernamePasswordAuthenticationFilter.class);
    }


}

总结
所以AuthenticationManager显式设置需要在继承了SecurityConfigurerAdapter的类中。