不久前我遇到了一个有趣的情况,导致Spring Security' AuthenticationManager
中出现无限循环(最终导致堆栈溢出)。几个月来,一切都按预期工作,但后来我决定将我的XML配置转移到仅代码配置。这是我在Java配置中的基本设置:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.my.company" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Disable default configuration
public SecurityConfig() {
super(true);
}
@Autowired
AuthenticationProviderImpl authenticationProvider;
@Autowired
MyAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter;
@Bean(name = "authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(WebSecurity web) throws Exception {
// Ignore requests of resources in security
web.ignoring().antMatchers("/resources/**")
// Ignore requests to authentication
.and().ignoring().antMatchers("/auth/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Define main authentication filter
http.addFilterBefore(authenticationTokenProcessingFilter,
UsernamePasswordAuthenticationFilter.class)
// Request path authorization
.authorizeRequests()
.antMatchers("/api/**")
.access("isAuthenticated()")
// Authentication provider
.and()
.authenticationProvider(authenticationProvider)
// Security failure exception handling
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
// Session Management
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// Default security HTTP headers
.and().headers().xssProtection().frameOptions()
.cacheControl().contentTypeOptions();
}
}
但是,我很快发现这个配置会导致我的AuthenticationProviderImpl
(实现Spring Security AuthenticationProvider
接口)出现问题。当实现的重写authenticate
方法抛出BadCredentialsException
时,该类中的完全相同的方法将永久再次调用,直到堆栈溢出。好消息是,我通过简单地覆盖configure(AuthenticationManagerBuilder builder)
中的SecurityConfig
并声明我在AuthenticationProvider
的实施而不是configure(HttpSecurity http)
来修复我的配置。这是固定版本:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.my.company" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Disable default configuration
public SecurityConfig() {
super(true);
}
@Autowired
AuthenticationProviderImpl authenticationProvider;
@Autowired
MyAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
AuthenticationTokenProcessingFilter authenticationTokenProcessingFilter;
@Bean(name = "authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(AuthenticationManagerBuilder builder) {
// Configure the authentication manager WITH the authentication
// provider. Not overriding this method causes very bad things to
// happen.
builder.authenticationProvider(authenticationProvider);
}
@Override
public void configure(WebSecurity web) throws Exception {
// Ignore requests of resources in security
web.ignoring().antMatchers("/resources/**")
// Ignore requests to authentication
.and().ignoring().antMatchers("/auth/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Define main authentication filter
http.addFilterBefore(authenticationTokenProcessingFilter,
UsernamePasswordAuthenticationFilter.class)
// Request path authorization
.authorizeRequests()
.antMatchers("/api/**")
.access("isAuthenticated()")
.and()
// Security failure exception handling
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
// Session Management
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// Default security HTTP headers
.and().headers().xssProtection().frameOptions()
.cacheControl().contentTypeOptions();
}
}
虽然我相信我的问题已通过固定配置解决,但我仍然不知道为什么当我的authenticate()
实现抛出异常时应用程序无限调用AuthenticationProvider
?我试图单步执行并检查Spring Security类,但我没有找到合乎逻辑的答案。感谢您的专业知识!
答案 0 :(得分:1)
几周前,我也重现了这种行为,see this thread on stackoverflow。
处理这个问题我发现当AuthenticationManager
在内部迭代它的关联AuthenticationProviders
列表时会发生循环,然后找到一个自定义提供程序并尝试使用已提供的提供程序进行身份验证找到。如果提供程序通过调用AuthenticationManager
将身份验证委托回authenticate()
,则您处于循环中。我猜你的AuthenticationProviderImpl
会做那样的事情吗?
java.util.List
的{{1}}内的提供商的顺序很重要。订单由您的配置提供,例如通过你最初尝试的做法:
AuthenticationManager
通过更改您的配置,您影响了附加到您的经理的内部管理的提供商列表,最终将解决您的代码。