Parcourir la source

Add setBasePath

Originally, it was thought that this feature would be rather uncommon;
however, given some feedback from the Boot team, it makes sense to make
this easier to configure.

Of specific note is migrating from an earlier version were the
servlet path did not need to be specified in authorizeHttpRequests.
Since it does in 7, this will be a significant migration for those
who have a servlet path configured. This setter simplifies that a great
deal, including simplifying Boot's support of it.

Closes gh-17579
Josh Cummings il y a 1 mois
Parent
commit
63e0a56bee

+ 24 - 2
config/src/main/java/org/springframework/security/config/web/PathPatternRequestMatcherBuilderFactoryBean.java

@@ -46,6 +46,8 @@ public final class PathPatternRequestMatcherBuilderFactoryBean implements
 
 	private final PathPatternParser parser;
 
+	private String basePath;
+
 	private ApplicationContext context;
 
 	private String beanName;
@@ -78,23 +80,43 @@ public final class PathPatternRequestMatcherBuilderFactoryBean implements
 	public PathPatternRequestMatcher.Builder getObject() throws Exception {
 		if (!this.context.containsBean(MVC_PATTERN_PARSER_BEAN_NAME)) {
 			PathPatternParser parser = (this.parser != null) ? this.parser : PathPatternParser.defaultInstance;
-			return PathPatternRequestMatcher.withPathPatternParser(parser);
+			return withPathPatternParser(parser);
 		}
 		PathPatternParser mvc = this.context.getBean(MVC_PATTERN_PARSER_BEAN_NAME, PathPatternParser.class);
 		PathPatternParser parser = (this.parser != null) ? this.parser : mvc;
 		if (mvc.equals(parser)) {
-			return PathPatternRequestMatcher.withPathPatternParser(parser);
+			return withPathPatternParser(parser);
 		}
 		throw new IllegalArgumentException("Spring Security and Spring MVC must use the same path pattern parser. "
 				+ "To have Spring Security use Spring MVC's [" + describe(mvc, MVC_PATTERN_PARSER_BEAN_NAME)
 				+ "] simply publish this bean [" + describe(this, this.beanName) + "] using its default constructor");
 	}
 
+	private PathPatternRequestMatcher.Builder withPathPatternParser(PathPatternParser parser) {
+		if (this.basePath == null) {
+			return PathPatternRequestMatcher.withPathPatternParser(parser);
+		}
+		else {
+			return PathPatternRequestMatcher.withPathPatternParser(parser).basePath(this.basePath);
+		}
+	}
+
 	@Override
 	public Class<?> getObjectType() {
 		return PathPatternRequestMatcher.Builder.class;
 	}
 
+	/**
+	 * Use this as the base path for patterns built by the resulting
+	 * {@link PathPatternRequestMatcher.Builder} instance
+	 * @param basePath the base path to use
+	 * @since 7.0
+	 * @see PathPatternRequestMatcher.Builder#basePath(String)
+	 */
+	public void setBasePath(String basePath) {
+		this.basePath = basePath;
+	}
+
 	@Override
 	public void setApplicationContext(ApplicationContext context) throws BeansException {
 		this.context = context;

+ 13 - 0
config/src/test/java/org/springframework/security/config/web/PathPatternRequestMatcherBuilderFactoryBeanTests.java

@@ -22,9 +22,11 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.security.web.servlet.TestMockHttpServletRequests;
 import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
 import org.springframework.web.util.pattern.PathPatternParser;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -75,6 +77,17 @@ class PathPatternRequestMatcherBuilderFactoryBeanTests {
 		verify(mvc).parse("/path/**");
 	}
 
+	@Test
+	void getObjectWhenBasePathThenUses() throws Exception {
+		PathPatternRequestMatcherBuilderFactoryBean factoryBean = new PathPatternRequestMatcherBuilderFactoryBean();
+		factoryBean.setApplicationContext(this.context);
+		factoryBean.setBasePath("/mvc");
+		PathPatternRequestMatcher.Builder builder = factoryBean.getObject();
+		PathPatternRequestMatcher matcher = builder.matcher("/path/**");
+		assertThat(matcher.matches(TestMockHttpServletRequests.get("/mvc/path/123").build())).isTrue();
+		assertThat(matcher.matches(TestMockHttpServletRequests.get("/path/123").build())).isFalse();
+	}
+
 	PathPatternRequestMatcherBuilderFactoryBean factoryBean() {
 		PathPatternRequestMatcherBuilderFactoryBean factoryBean = new PathPatternRequestMatcherBuilderFactoryBean();
 		factoryBean.setApplicationContext(this.context);