Move PathPatternRequestMatcher.Builder to Shared Object

This commit changes the DSL to look for a shared object
instead of publishing a bean for PathPatternRequestMatcher.Builder.

Closes gh-17746
This commit is contained in:
Josh Cummings 2025-08-18 06:31:31 -06:00
parent 006f638c0a
commit aeb2dbc2b6
No known key found for this signature in database
GPG Key ID: 869B37A20E876129
10 changed files with 119 additions and 51 deletions

View File

@ -27,11 +27,13 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher; import org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.function.ThrowingSupplier;
/** /**
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for * A base class for registering {@link RequestMatcher}'s. For example, it might allow for
@ -52,6 +54,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
private final Log logger = LogFactory.getLog(getClass()); private final Log logger = LogFactory.getLog(getClass());
private PathPatternRequestMatcher.Builder requestMatcherBuilder;
protected final void setApplicationContext(ApplicationContext context) { protected final void setApplicationContext(ApplicationContext context) {
this.context = context; this.context = context;
} }
@ -140,7 +144,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
+ "Spring Security, leaving out the leading slash will result in an exception."); + "Spring Security, leaving out the leading slash will result in an exception.");
} }
Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest"); Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
PathPatternRequestMatcher.Builder builder = this.context.getBean(PathPatternRequestMatcher.Builder.class); PathPatternRequestMatcher.Builder builder = getRequestMatcherBuilder();
List<RequestMatcher> matchers = new ArrayList<>(); List<RequestMatcher> matchers = new ArrayList<>();
for (String pattern : patterns) { for (String pattern : patterns) {
matchers.add(builder.matcher(method, pattern)); matchers.add(builder.matcher(method, pattern));
@ -148,6 +152,23 @@ public abstract class AbstractRequestMatcherRegistry<C> {
return requestMatchers(matchers.toArray(new RequestMatcher[0])); return requestMatchers(matchers.toArray(new RequestMatcher[0]));
} }
private PathPatternRequestMatcher.Builder getRequestMatcherBuilder() {
if (this.requestMatcherBuilder != null) {
return this.requestMatcherBuilder;
}
this.requestMatcherBuilder = this.context.getBeanProvider(PathPatternRequestMatcher.Builder.class)
.getIfUnique(() -> constructRequestMatcherBuilder(this.context));
return this.requestMatcherBuilder;
}
private PathPatternRequestMatcher.Builder constructRequestMatcherBuilder(ApplicationContext context) {
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder = new PathPatternRequestMatcherBuilderFactoryBean();
requestMatcherBuilder.setApplicationContext(context);
requestMatcherBuilder.setBeanFactory(context.getAutowireCapableBeanFactory());
requestMatcherBuilder.setBeanName(requestMatcherBuilder.toString());
return ThrowingSupplier.of(requestMatcherBuilder::getObject).get();
}
private boolean anyPathsDontStartWithLeadingSlash(String... patterns) { private boolean anyPathsDontStartWithLeadingSlash(String... patterns) {
for (String pattern : patterns) { for (String pattern : patterns) {
if (!pattern.startsWith("/")) { if (!pattern.startsWith("/")) {

View File

@ -2058,7 +2058,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
*/ */
public HttpSecurity securityMatcher(String... patterns) { public HttpSecurity securityMatcher(String... patterns) {
List<RequestMatcher> matchers = new ArrayList<>(); List<RequestMatcher> matchers = new ArrayList<>();
PathPatternRequestMatcher.Builder builder = getContext().getBean(PathPatternRequestMatcher.Builder.class); PathPatternRequestMatcher.Builder builder = getSharedObject(PathPatternRequestMatcher.Builder.class);
for (String pattern : patterns) { for (String pattern : patterns) {
matchers.add(builder.matcher(pattern)); matchers.add(builder.matcher(pattern));
} }

View File

@ -1,31 +0,0 @@
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Fallback;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
class AuthorizationConfiguration {
@Bean
@Fallback
PathPatternRequestMatcherBuilderFactoryBean pathPatternRequestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
}

View File

@ -83,7 +83,7 @@ import org.springframework.security.web.SecurityFilterChain;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Documented @Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class, ObservationImportSelector.class, AuthorizationConfiguration.class }) HttpSecurityConfiguration.class, ObservationImportSelector.class })
@EnableGlobalAuthentication @EnableGlobalAuthentication
public @interface EnableWebSecurity { public @interface EnableWebSecurity {

View File

@ -38,12 +38,15 @@ import org.springframework.security.config.annotation.authentication.configurers
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer; import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter; import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.util.function.ThrowingSupplier;
import org.springframework.web.accept.ContentNegotiationStrategy; import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy; import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@ -161,9 +164,18 @@ class HttpSecurityConfiguration {
Map<Class<?>, Object> sharedObjects = new HashMap<>(); Map<Class<?>, Object> sharedObjects = new HashMap<>();
sharedObjects.put(ApplicationContext.class, this.context); sharedObjects.put(ApplicationContext.class, this.context);
sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy); sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
sharedObjects.put(PathPatternRequestMatcher.Builder.class, constructRequestMatcherBuilder(this.context));
return sharedObjects; return sharedObjects;
} }
private PathPatternRequestMatcher.Builder constructRequestMatcherBuilder(ApplicationContext context) {
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder = new PathPatternRequestMatcherBuilderFactoryBean();
requestMatcherBuilder.setApplicationContext(context);
requestMatcherBuilder.setBeanFactory(context.getAutowireCapableBeanFactory());
requestMatcherBuilder.setBeanName(requestMatcherBuilder.toString());
return ThrowingSupplier.of(requestMatcherBuilder::getObject).get();
}
static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder { static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {
private PasswordEncoder defaultPasswordEncoder; private PasswordEncoder defaultPasswordEncoder;

View File

@ -39,8 +39,6 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
private SecurityContextHolderStrategy securityContextHolderStrategy; private SecurityContextHolderStrategy securityContextHolderStrategy;
private PathPatternRequestMatcher.Builder requestMatcherBuilder;
/** /**
* Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh * Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
* version of the configuration can be applied. * version of the configuration can be applied.
@ -69,12 +67,7 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
} }
protected PathPatternRequestMatcher.Builder getRequestMatcherBuilder() { protected PathPatternRequestMatcher.Builder getRequestMatcherBuilder() {
if (this.requestMatcherBuilder != null) { return getBuilder().getSharedObject(PathPatternRequestMatcher.Builder.class);
return this.requestMatcherBuilder;
}
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
this.requestMatcherBuilder = context.getBean(PathPatternRequestMatcher.Builder.class);
return this.requestMatcherBuilder;
} }
} }

View File

@ -17,6 +17,7 @@
package org.springframework.security.config.annotation.web; package org.springframework.security.config.annotation.web;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import jakarta.servlet.DispatcherType; import jakarta.servlet.DispatcherType;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -68,8 +69,8 @@ public class AbstractRequestMatcherRegistryTests {
ObjectProvider<ObjectPostProcessor<Object>> given = this.context.getBeanProvider(type); ObjectProvider<ObjectPostProcessor<Object>> given = this.context.getBeanProvider(type);
given(given).willReturn(postProcessors); given(given).willReturn(postProcessors);
given(postProcessors.getObject()).willReturn(NO_OP_OBJECT_POST_PROCESSOR); given(postProcessors.getObject()).willReturn(NO_OP_OBJECT_POST_PROCESSOR);
given(this.context.getBean(PathPatternRequestMatcher.Builder.class)) given(this.context.getBeanProvider(PathPatternRequestMatcher.Builder.class))
.willReturn(PathPatternRequestMatcher.withDefaults()); .willReturn(new SingleObjectProvider<>(PathPatternRequestMatcher.withDefaults()));
this.matcherRegistry.setApplicationContext(this.context); this.matcherRegistry.setApplicationContext(this.context);
} }
@ -165,4 +166,19 @@ public class AbstractRequestMatcherRegistryTests {
} }
private static final class SingleObjectProvider<T> implements ObjectProvider<T> {
private final T object;
private SingleObjectProvider(T object) {
this.object = object;
}
@Override
public Stream<T> stream() {
return Stream.of(this.object);
}
}
} }

View File

@ -54,6 +54,7 @@ import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.observation.SecurityObservationSettings; import org.springframework.security.config.observation.SecurityObservationSettings;
import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
@ -1051,12 +1052,19 @@ public class AuthorizeHttpRequestsConfigurerTests {
@EnableWebSecurity @EnableWebSecurity
static class ServletPathConfig { static class ServletPathConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requesMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off // @formatter:off
return http return http
.authorizeHttpRequests((authorize) -> authorize .authorizeHttpRequests((authorize) -> authorize
.requestMatchers(builder.basePath("/spring").matcher("/")).hasRole("ADMIN") .requestMatchers(builder.matcher("/")).hasRole("ADMIN")
) )
.build(); .build();
// @formatter:on // @formatter:on

View File

@ -32,6 +32,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterChainProxy;
@ -157,6 +158,11 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc @EnableWebMvc
static class MultiMvcMatcherInLambdaConfig { static class MultiMvcMatcherInLambdaConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean @Bean
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
@ -204,6 +210,11 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc @EnableWebMvc
static class MultiMvcMatcherConfig { static class MultiMvcMatcherConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean @Bean
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain first(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
@ -249,6 +260,11 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc @EnableWebMvc
static class MvcMatcherConfig { static class MvcMatcherConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off // @formatter:off
@ -283,6 +299,11 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc @EnableWebMvc
static class RequestMatchersMvcMatcherConfig { static class RequestMatchersMvcMatcherConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off // @formatter:off
@ -318,6 +339,11 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc @EnableWebMvc
static class RequestMatchersMvcMatcherInLambdaConfig { static class RequestMatchersMvcMatcherInLambdaConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off // @formatter:off
@ -350,6 +376,11 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc @EnableWebMvc
static class RequestMatchersMvcMatcherServeltPathConfig { static class RequestMatchersMvcMatcherServeltPathConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off // @formatter:off
@ -386,6 +417,11 @@ public class HttpSecurityRequestMatchersTests {
@EnableWebMvc @EnableWebMvc
static class RequestMatchersMvcMatcherServletPathInLambdaConfig { static class RequestMatchersMvcMatcherServletPathInLambdaConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
// @formatter:off // @formatter:off

View File

@ -32,6 +32,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
@ -354,14 +355,20 @@ public class HttpSecuritySecurityMatchersTests {
@Import(UsersConfig.class) @Import(UsersConfig.class)
static class SecurityMatchersMvcMatcherServletPathConfig { static class SecurityMatchersMvcMatcherServletPathConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean @Bean
SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
// @formatter:off // @formatter:off
http http
.securityMatchers((security) -> security .securityMatchers((security) -> security
.requestMatchers(spring.matcher("/path")) .requestMatchers(builder.matcher("/path"))
.requestMatchers(spring.matcher("/never-match")) .requestMatchers(builder.matcher("/never-match"))
) )
.httpBasic(withDefaults()) .httpBasic(withDefaults())
.authorizeHttpRequests((authorize) -> authorize .authorizeHttpRequests((authorize) -> authorize
@ -388,14 +395,20 @@ public class HttpSecuritySecurityMatchersTests {
@Import(UsersConfig.class) @Import(UsersConfig.class)
static class SecurityMatchersMvcMatcherServletPathInLambdaConfig { static class SecurityMatchersMvcMatcherServletPathInLambdaConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean @Bean
SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { SecurityFilterChain appSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception {
PathPatternRequestMatcher.Builder spring = builder.basePath("/spring");
// @formatter:off // @formatter:off
http http
.securityMatchers((matchers) -> matchers .securityMatchers((matchers) -> matchers
.requestMatchers(spring.matcher("/path")) .requestMatchers(builder.matcher("/path"))
.requestMatchers(spring.matcher("/never-match")) .requestMatchers(builder.matcher("/never-match"))
) )
.httpBasic(withDefaults()) .httpBasic(withDefaults())
.authorizeHttpRequests((authorize) -> authorize .authorizeHttpRequests((authorize) -> authorize