DefaultSecurityFilterChain инициализируется два раза при запуске spring-boot-starter-security со свего самописного стартера
Прошу помощи, до этого еще не писал свои собственнве стартеры. Я решил вынести кофигурацию spring security в отдельный старетр что б мог его использовать в других микросервисах. Теперь при запуске проекта с использованием моего arigato-security-starter в качестве зависимости в логах видно что DefaultSecurityFilterChain инициализируется два раза. По этой причине я так понимаю что когда я обращаюсь на защищенный endpoint с токеном, я не попадаю на свой самописный фильтр CustomAuthenticationFilter и всегда получаю статус ошибки 401 Unauthorized.
Вот краткий код и настройка моего стартера
2024-04-20T13:52:22.634+05:00 INFO 16540 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 610 ms
2024-04-20T13:52:22.920+05:00 INFO 16540 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@4b765e92, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4665428b, org.springframework.security.web.context.SecurityContextHolderFilter@ccd341d, org.springframework.security.web.header.HeaderWriterFilter@63f40ca0, org.springframework.web.filter.CorsFilter@4a70d302, org.springframework.security.web.csrf.CsrfFilter@59636c47, org.springframework.security.web.authentication.logout.LogoutFilter@2415e4c7, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@6b63abdc, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@16b3c905, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7fd99443, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@241fbec, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6ee5f485, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@20d19f2c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@622d7e4, org.springframework.security.web.access.ExceptionTranslationFilter@324b6a56, org.springframework.security.web.access.intercept.AuthorizationFilter@6b37df8e]
2024-04-20T13:52:22.924+05:00 INFO 16540 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@587c5c1, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@528c8c1, org.springframework.security.web.context.SecurityContextHolderFilter@29f3c438, org.springframework.security.web.header.HeaderWriterFilter@2abafa97, ru.arigato.securitystarter.config.filters.CustomAuthenticationFilter@7fb53256, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5460edd3, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5dbbb292, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1f78d415, org.springframework.security.web.session.SessionManagementFilter@40717ed, org.springframework.security.web.access.ExceptionTranslationFilter@724bf25f, org.springframework.security.web.access.intercept.AuthorizationFilter@565aa4ac]
2024-04-20T13:52:22.962+05:00 INFO 16540 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path ```
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
@Configuration
@AllArgsConstructor
@EnableWebSecurity
@EnableConfigurationProperties(SecurityProperties.class)
@ComponentScan("ru.arigato.securitystarter.config")
public class SecurityConfig {
private final SecurityProperties securityProperties;
private final CustomAuthenticationFilter customAuthenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.logout(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterAt(customAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(authorizeRequests -> {
authorizeRequests.anyRequest().authenticated();
})
.build();
}
}
@Component
@AllArgsConstructor
public class CustomAuthenticationFilter extends OncePerRequestFilter {
private final CustomAuthenticationManager customAuthenticationManager;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//какой то код.....
Authentication authentication = customAuthenticationManager.authenticate(jwtAuthentication);
}
}
@Component
@AllArgsConstructor
public class CustomAuthenticationManager implements AuthenticationManager {
private final List<AuthenticationProvider> provider;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//....
}}
@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//......
}
@Override
public boolean supports(Class<?> authentication) {
return JwtAuthentication.class.equals(authentication);
}
}
resources
.META-INF
.spring
.org.springframework.boot.autoconfigure.AutoConfiguration.imports
ru.arigato.securitystarter.config.SecurityConfig
resources
.META-INF
org.springframework.boot.env.EnvironmentPostProcessor=ru.arigato.securitystarter.config.EnvPostProcessor
Ответы (2 шт):
Не знаю как это работает, но я чисто случаной заметил что если мой путь проекта всместа
ru.arigato.securitystarter.config
заменить на
dev.arigato.securitystarter.config
то все работает и DefaultSecurityFilterChain инициализируется один раз. И все запроса попадают на мой самописный фильтр.
Возникла та же проблема. В самописном стартере секьюрити фильтр не подтягивает. Только спустя сутки поиска, нашёл проблему похожую на мою, и вот я здесь.
Так же две цепочки фильтров образуются в логах. Наименование пакетов не могу сделать одинаковым.
Были ли найдены другие решения?
Скорее всего, spring security starter сканируется по пакетам, и для стартера он будет своим, приходиться переопределять. Моё решение, сделал шаблон, который потом в основном проекте делаю бином передавая в конструктор всё нужное
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final SecurityTemplate template;
public SecurityConfig(TokenFilter tokenFilter, ErrorEndpoint errorEndpoint) {
this.template = new SecurityTemplate(errorEndpoint, tokenFilter);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
return template.filterChain(httpSecurity, null);
}
}