Skip to content

Commit

Permalink
Avoid unnecessary instantiation of HttpSecurity when a SecurityFilter…
Browse files Browse the repository at this point in the history
…Chain bean is provided

Signed-off-by: DingHao <dh.hiekn@gmail.com>
  • Loading branch information
kse-music committed Jan 9, 2025
1 parent 0e3cfd1 commit 2623bf8
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,7 @@
import jakarta.servlet.Filter;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
Expand Down Expand Up @@ -79,9 +80,6 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa

private ClassLoader beanClassLoader;

@Autowired(required = false)
private HttpSecurity httpSecurity;

@Bean
public static DelegatingApplicationListener delegatingApplicationListener() {
return new DelegatingApplicationListener();
Expand All @@ -99,14 +97,15 @@ public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler(
* @throws Exception
*/
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
public Filter springSecurityFilterChain(ObjectProvider<HttpSecurity> provider) throws Exception {
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
if (!hasFilterChain) {
this.webSecurity.addSecurityFilterChainBuilder(() -> {
this.httpSecurity.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());
this.httpSecurity.formLogin(Customizer.withDefaults());
this.httpSecurity.httpBasic(Customizer.withDefaults());
return this.httpSecurity.build();
HttpSecurity httpSecurity = provider.getObject();
httpSecurity.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());
httpSecurity.formLogin(Customizer.withDefaults());
httpSecurity.httpBasic(Customizer.withDefaults());
return httpSecurity.build();
});
}
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,8 +27,10 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
Expand Down Expand Up @@ -326,6 +328,38 @@ public void loadConfigWhenTwoSecurityFilterChainsPresentAndSecondWithAnyRequestT
.isInstanceOf(IllegalArgumentException.class);
}

@Test
public void avoidUnnecessaryHttpSecurityInstantiationWhenProvideOneSecurityFilterChain() {
this.spring.register(SecurityFilterChainConfig.class).autowire();
assertThat(this.spring.getContext().getBean(CustomBeanPostProcessor.class).instantiationCount).isEqualTo(1);
}

@Configuration
@EnableWebSecurity
@Import(CustomBeanPostProcessor.class)
static class SecurityFilterChainConfig {

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).build();
}

}

static class CustomBeanPostProcessor implements BeanPostProcessor {

int instantiationCount = 0;

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof HttpSecurity) {
this.instantiationCount++;
}
return bean;
}

}

private void assertAnotherUserPermission(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
Authentication anotherUser = new TestingAuthenticationToken("anotherUser", "password", "ROLE_ANOTHER");
assertThat(privilegeEvaluator.isAllowed("/user", anotherUser)).isFalse();
Expand Down

0 comments on commit 2623bf8

Please sign in to comment.