使用AuthenticationManager时,Spring Boot身份验证会导致递归和StackOverflowError

jhdbpxl9  于 2022-11-23  发布在  Spring
关注(0)|答案(1)|浏览(252)

为什么使用AuthenticationManager会导致StackOverflowError?在身份验证过程中的某个地方似乎有一个递归调用,但不幸的是我不知道如何应对这种情况。
下面是代码:

@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {

    AuthenticationManagerBuilder authManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);

    authManagerBuilder.inMemoryAuthentication().withUser("user").password("{noop}password").roles("USER");

    return authManagerBuilder.build();
}

使用正确的数据登录可以正常工作,但一旦用户名或密码不正确,就会出现以下问题之一:用户名错误导致无限循环:

...
o.s.s.a.dao.DaoAuthenticationProvider    : Failed to find user 'admin'
o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/1)
o.s.s.a.dao.DaoAuthenticationProvider    : Failed to find user 'admin'
o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/1)
o.s.s.a.dao.DaoAuthenticationProvider    : Failed to find user 'admin'
o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/1)
...

使用正确的用户名但错误的密码,递归会导致StackOverflowError:

...
o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/1)
o.s.s.a.dao.DaoAuthenticationProvider    : Failed to authenticate since password does not match stored value
o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/1)
o.s.s.a.dao.DaoAuthenticationProvider    : Failed to authenticate since password does not match stored value
o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/1)
o.s.s.a.dao.DaoAuthenticationProvider    : Failed to authenticate since password does not match stored value
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause

java.lang.StackOverflowError: null
    at java.base/java.util.stream.IntPipeline.forEachWithCancel(IntPipeline.java:161) ~[na:na]
...

除了SecurityFilterChain和PasswordEncoder之外,没有其他Bean集。所以我想知道为什么传统使用InMemoryUserDetailsManager Bean可以工作,但是在AuthenticationManager的帮助下使用相同的功能会导致问题?
编辑:因为请求,这里是完整的代码示例:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain defaultFilterChain(HttpSecurity http, AuthenticationManager authManager) throws Exception {
        return http
                .authorizeRequests(auth -> auth
                        .mvcMatchers("/").permitAll()
                        .mvcMatchers("/**").access("hasRole('USER')"))

                .formLogin(FormLoginConfigurer::permitAll)
                .authenticationManager(authManager)
                .build();
    }

    @Bean
    public AuthenticationManager authManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authManagerBuilder =
                http.getSharedObject(AuthenticationManagerBuilder.class);

        authManagerBuilder.inMemoryAuthentication()
                .withUser("user")
                .password("{noop}password")
                .roles("USER");

        return authManagerBuilder.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}
hgb9j2n6

hgb9j2n61#

从Spring 5.4开始,推荐转向基于组件的安全配置。实际上,WebSecurityConfigurerAdapter在Spring Security 5.7.0-M2中已经被弃用。
对于本示例中所需的身份验证类型,我认为您可以使用以下方法,如官方文档中所示:

@Configuration
public class SecurityConfiguration {
    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }
}

本文还介绍了其他场景,例如创建自定义的AuthenticationManager:https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter#ldap-authentication

相关问题