Skip to content

Commit 1de2f36

Browse files
committed
Avoid unnecessary instantiation of HttpSecurity when a SecurityFilterChain bean is provided
Signed-off-by: DingHao <[email protected]>
1 parent 0e3cfd1 commit 1de2f36

File tree

2 files changed

+43
-10
lines changed

2 files changed

+43
-10
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import jakarta.servlet.Filter;
2424

2525
import org.springframework.beans.factory.BeanClassLoaderAware;
26+
import org.springframework.beans.factory.ObjectProvider;
2627
import org.springframework.beans.factory.annotation.Autowired;
2728
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
2829
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -79,9 +80,6 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
7980

8081
private ClassLoader beanClassLoader;
8182

82-
@Autowired(required = false)
83-
private HttpSecurity httpSecurity;
84-
8583
@Bean
8684
public static DelegatingApplicationListener delegatingApplicationListener() {
8785
return new DelegatingApplicationListener();
@@ -99,14 +97,15 @@ public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler(
9997
* @throws Exception
10098
*/
10199
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
102-
public Filter springSecurityFilterChain() throws Exception {
100+
public Filter springSecurityFilterChain(ObjectProvider<HttpSecurity> provider) throws Exception {
103101
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
104102
if (!hasFilterChain) {
105103
this.webSecurity.addSecurityFilterChainBuilder(() -> {
106-
this.httpSecurity.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());
107-
this.httpSecurity.formLogin(Customizer.withDefaults());
108-
this.httpSecurity.httpBasic(Customizer.withDefaults());
109-
return this.httpSecurity.build();
104+
HttpSecurity httpSecurity = provider.getObject();
105+
httpSecurity.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());
106+
httpSecurity.formLogin(Customizer.withDefaults());
107+
httpSecurity.httpBasic(Customizer.withDefaults());
108+
return httpSecurity.build();
110109
});
111110
}
112111
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {

config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java

+35-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,8 +27,10 @@
2727
import org.junit.jupiter.api.Test;
2828
import org.junit.jupiter.api.extension.ExtendWith;
2929

30+
import org.springframework.beans.BeansException;
3031
import org.springframework.beans.factory.BeanCreationException;
3132
import org.springframework.beans.factory.annotation.Autowired;
33+
import org.springframework.beans.factory.config.BeanPostProcessor;
3234
import org.springframework.context.annotation.Bean;
3335
import org.springframework.context.annotation.Configuration;
3436
import org.springframework.context.annotation.Import;
@@ -326,6 +328,12 @@ public void loadConfigWhenTwoSecurityFilterChainsPresentAndSecondWithAnyRequestT
326328
.isInstanceOf(IllegalArgumentException.class);
327329
}
328330

331+
@Test
332+
public void avoidUnnecessaryHttpSecurityInstantiationWhenProvideOneSecurityFilterChain() {
333+
this.spring.register(SecurityFilterChainConfig.class).autowire();
334+
assertThat(this.spring.getContext().getBean(CustomBeanPostProcessor.class).instantiationCount).isEqualTo(1);
335+
}
336+
329337
private void assertAnotherUserPermission(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
330338
Authentication anotherUser = new TestingAuthenticationToken("anotherUser", "password", "ROLE_ANOTHER");
331339
assertThat(privilegeEvaluator.isAllowed("/user", anotherUser)).isFalse();
@@ -347,6 +355,32 @@ private void assertUserPermissions(WebInvocationPrivilegeEvaluator privilegeEval
347355
assertThat(privilegeEvaluator.isAllowed("/another", user)).isTrue();
348356
}
349357

358+
@Configuration
359+
@EnableWebSecurity
360+
@Import(CustomBeanPostProcessor.class)
361+
static class SecurityFilterChainConfig {
362+
363+
@Bean
364+
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
365+
return http.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).build();
366+
}
367+
368+
}
369+
370+
static class CustomBeanPostProcessor implements BeanPostProcessor {
371+
372+
int instantiationCount = 0;
373+
374+
@Override
375+
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
376+
if (bean instanceof HttpSecurity) {
377+
this.instantiationCount++;
378+
}
379+
return bean;
380+
}
381+
382+
}
383+
350384
@Configuration
351385
@EnableWebSecurity
352386
@Import(AuthenticationTestConfiguration.class)

0 commit comments

Comments
 (0)