为什么使用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();
}
}
1条答案
按热度按时间hgb9j2n61#
从Spring 5.4开始,推荐转向基于组件的安全配置。实际上,
WebSecurityConfigurerAdapter
在Spring Security 5.7.0-M2中已经被弃用。对于本示例中所需的身份验证类型,我认为您可以使用以下方法,如官方文档中所示:
本文还介绍了其他场景,例如创建自定义的
AuthenticationManager
:https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter#ldap-authentication