2
0
Эх сурвалжийг харах

Deprecate MvcRequestMatcher

Closes gh-16631
Josh Cummings 5 сар өмнө
parent
commit
05fdcd6a08

+ 1 - 1
docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc

@@ -583,7 +583,7 @@ Generally speaking, you can use `requestMatchers(String)` as demonstrated above.
 
 
 However, if you have authorization rules from multiple servlets, you need to specify those:
 However, if you have authorization rules from multiple servlets, you need to specify those:
 
 
-.Match by MvcRequestMatcher
+.Match by PathPatternRequestMatcher
 [tabs]
 [tabs]
 ======
 ======
 Java::
 Java::

+ 114 - 195
docs/modules/ROOT/pages/servlet/integrations/mvc.adoc

@@ -22,45 +22,13 @@ This means that, if you use more advanced options, such as integrating with `Web
 ====
 ====
 
 
 [[mvc-requestmatcher]]
 [[mvc-requestmatcher]]
-== MvcRequestMatcher
+== PathPatternRequestMatcher
 
 
-Spring Security provides deep integration with how Spring MVC matches on URLs with `MvcRequestMatcher`.
+Spring Security provides deep integration with how Spring MVC matches on URLs with `PathPatternRequestMatcher`.
 This is helpful to ensure that your Security rules match the logic used to handle your requests.
 This is helpful to ensure that your Security rules match the logic used to handle your requests.
 
 
-To use `MvcRequestMatcher`, you must place the Spring Security Configuration in the same `ApplicationContext` as your `DispatcherServlet`.
-This is necessary because Spring Security's `MvcRequestMatcher` expects a `HandlerMappingIntrospector` bean with the name of `mvcHandlerMappingIntrospector` to be registered by your Spring MVC configuration that is used to perform the matching.
-
-For a `web.xml` file, this means that you should place your configuration in the `DispatcherServlet.xml`:
-
-[source,xml]
-----
-<listener>
-  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
-</listener>
-
-<!-- All Spring Configuration (both MVC and Security) are in /WEB-INF/spring/ -->
-<context-param>
-  <param-name>contextConfigLocation</param-name>
-  <param-value>/WEB-INF/spring/*.xml</param-value>
-</context-param>
-
-<servlet>
-  <servlet-name>spring</servlet-name>
-  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
-  <!-- Load from the ContextLoaderListener -->
-  <init-param>
-    <param-name>contextConfigLocation</param-name>
-    <param-value></param-value>
-  </init-param>
-</servlet>
-
-<servlet-mapping>
-  <servlet-name>spring</servlet-name>
-  <url-pattern>/</url-pattern>
-</servlet-mapping>
-----
-
-The following `WebSecurityConfiguration` in placed in the  `ApplicationContext` of the `DispatcherServlet`.
+`PathPatternRequestMatcher` must use the same `PathPatternParser` as Spring MVC.
+If you are not customizing the `PathPatternParser`, then you can do:
 
 
 [tabs]
 [tabs]
 ======
 ======
@@ -68,70 +36,9 @@ Java::
 +
 +
 [source,java,role="primary"]
 [source,java,role="primary"]
 ----
 ----
-public class SecurityInitializer extends
-    AbstractAnnotationConfigDispatcherServletInitializer {
-
-  @Override
-  protected Class<?>[] getRootConfigClasses() {
-    return null;
-  }
-
-  @Override
-  protected Class<?>[] getServletConfigClasses() {
-    return new Class[] { RootConfiguration.class,
-        WebMvcConfiguration.class };
-  }
-
-  @Override
-  protected String[] getServletMappings() {
-    return new String[] { "/" };
-  }
-}
-----
-
-Kotlin::
-+
-[source,kotlin,role="secondary"]
-----
-class SecurityInitializer : AbstractAnnotationConfigDispatcherServletInitializer() {
-    override fun getRootConfigClasses(): Array<Class<*>>? {
-        return null
-    }
-
-    override fun getServletConfigClasses(): Array<Class<*>> {
-        return arrayOf(
-            RootConfiguration::class.java,
-            WebMvcConfiguration::class.java
-        )
-    }
-
-    override fun getServletMappings(): Array<String> {
-        return arrayOf("/")
-    }
-}
-----
-======
-
-[NOTE]
-====
-We always recommend that you provide authorization rules by matching on the `HttpServletRequest` and method security.
-
-Providing authorization rules by matching on `HttpServletRequest` is good, because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface].
-Method security ensures that, if someone has bypassed the web authorization rules, your application is still secured.
-This is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defense in Depth]
-====
-
-Consider a controller that is mapped as follows:
-
-[tabs]
-======
-Java::
-+
-[source,java,role="primary"]
-----
-@RequestMapping("/admin")
-public String admin() {
-	// ...
+@Bean
+PathPatternRequestMatcherBuilderFactoryBean usePathPattern() {
+	return new PathPatternRequestMatcherBuilderFactoryBean();
 }
 }
 ----
 ----
 
 
@@ -139,114 +46,34 @@ Kotlin::
 +
 +
 [source,kotlin,role="secondary"]
 [source,kotlin,role="secondary"]
 ----
 ----
-@RequestMapping("/admin")
-fun admin(): String {
-    // ...
-}
-----
-======
-
-To restrict access to this controller method to admin users, you can provide authorization rules by matching on the `HttpServletRequest` with the following:
-
-[tabs]
-======
-Java::
-+
-[source,java,role="primary"]
-----
 @Bean
 @Bean
-public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-	http
-		.authorizeHttpRequests((authorize) -> authorize
-			.requestMatchers("/admin").hasRole("ADMIN")
-		);
-	return http.build();
+fun usePathPattern(): PathPatternRequestMatcherBuilderFactoryBean {
+    return PathPatternRequestMatcherBuilderFactoryBean()
 }
 }
 ----
 ----
 
 
-Kotlin::
+Xml::
 +
 +
-[source,kotlin,role="secondary"]
+[source,xml,role="secondary"]
 ----
 ----
-@Bean
-open fun filterChain(http: HttpSecurity): SecurityFilterChain {
-    http {
-        authorizeHttpRequests {
-            authorize("/admin", hasRole("ADMIN"))
-        }
-    }
-    return http.build()
-}
+<b:bean class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>
 ----
 ----
 ======
 ======
 
 
-The following listing does the same thing in XML:
-
-[source,xml]
-----
-<http>
-	<intercept-url pattern="/admin" access="hasRole('ADMIN')"/>
-</http>
-----
-
-With either configuration, the `/admin` URL requires the authenticated user to be an admin user.
-However, depending on our Spring MVC configuration, the `/admin.html` URL also maps to our `admin()` method.
-Additionally, depending on our Spring MVC configuration, the `/admin` URL also maps to our `admin()` method.
+and Spring Security will find the appropriate Spring MVC configuration for you.
 
 
-The problem is that our security rule protects only  `/admin`.
-We could add additional rules for all the permutations of Spring MVC, but this would be quite verbose and tedious.
+If you *are* customizing Spring MVC's `PathPatternParser` instance, you will need to <<security-mvc-same-application-context, configure Spring Security and Spring MVC in the same `ApplicationContext`>>.
 
 
-Fortunately, when using the `requestMatchers` DSL method, Spring Security automatically creates a `MvcRequestMatcher` if it detects that Spring MVC is available in the classpath.
-Therefore, it will protect the same URLs that Spring MVC will match on by using Spring MVC to match on the URL.
-
-One common requirement when using Spring MVC is to specify the servlet path property.
-
-For Java-based Configuration, you can use the `MvcRequestMatcher.Builder` to create multiple `MvcRequestMatcher` instances that share the same servlet path:
-
-[source,java,role="primary"]
-----
-@Bean
-public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
-	MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector).servletPath("/path");
-	http
-		.authorizeHttpRequests((authorize) -> authorize
-			.requestMatchers(mvcMatcherBuilder.pattern("/admin")).hasRole("ADMIN")
-			.requestMatchers(mvcMatcherBuilder.pattern("/user")).hasRole("USER")
-		);
-	return http.build();
-}
-----
+[NOTE]
+====
+We always recommend that you provide authorization rules by matching on the `HttpServletRequest` and method security.
 
 
-For Kotlin and XML, this happens when you specify the servlet path for each path like so:
+Providing authorization rules by matching on `HttpServletRequest` is good, because it happens very early in the code path and helps reduce the https://en.wikipedia.org/wiki/Attack_surface[attack surface].
+Method security ensures that, if someone has bypassed the web authorization rules, your application is still secured.
+This is known as https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[Defense in Depth]
+====
 
 
-[tabs]
-======
-Kotlin::
-+
-[source,kotlin,role="secondary"]
-----
-@Bean
-open fun filterChain(http: HttpSecurity): SecurityFilterChain {
-    http {
-        authorizeHttpRequests {
-            authorize("/admin/**", "/mvc", hasRole("ADMIN"))
-            authorize("/user/**", "/mvc", hasRole("USER"))
-        }
-    }
-    return http.build()
-}
-----
-
-Xml::
-+
-[source,xml, role="secondary"]
-----
-<http request-matcher="mvc">
-	<intercept-url pattern="/admin/**" servlet-path="/mvc" access="hasRole('ADMIN')"/>
-    <intercept-url pattern="/user/**" servlet-path="/mvc" access="hasRole('USER')"/>
-</http>
-----
-======
+Now that Spring MVC is integrated with Spring Security, you are ready to write some xref:servlet/authorization/authorize-http-requests.adoc[authorization rules] that will use `PathPatternRequestMatcher`.
 
 
 [[mvc-authentication-principal]]
 [[mvc-authentication-principal]]
 == @AuthenticationPrincipal
 == @AuthenticationPrincipal
@@ -766,3 +593,95 @@ class CsrfController {
 
 
 It is important to keep the `CsrfToken` a secret from other domains.
 It is important to keep the `CsrfToken` a secret from other domains.
 This means that, if you use https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should *NOT* expose the `CsrfToken` to any external domains.
 This means that, if you use https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], you should *NOT* expose the `CsrfToken` to any external domains.
+
+[[security-mvc-same-application-context]]
+== Configuring Spring MVC and Spring Security in the Same Application Context
+
+If you are using Boot, Spring MVC and Spring Security are in the same application context by default.
+
+Otherwise, for Java Config, including both `@EnableWebMvc` and `@EnableWebSecurity` will construct Spring Security and Spring MVC components in the same context.
+
+Of, if you are using ``ServletListener``s you can do:
+
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+public class SecurityInitializer extends
+    AbstractAnnotationConfigDispatcherServletInitializer {
+
+  @Override
+  protected Class<?>[] getRootConfigClasses() {
+    return null;
+  }
+
+  @Override
+  protected Class<?>[] getServletConfigClasses() {
+    return new Class[] { RootConfiguration.class,
+        WebMvcConfiguration.class };
+  }
+
+  @Override
+  protected String[] getServletMappings() {
+    return new String[] { "/" };
+  }
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+class SecurityInitializer : AbstractAnnotationConfigDispatcherServletInitializer() {
+    override fun getRootConfigClasses(): Array<Class<*>>? {
+        return null
+    }
+
+    override fun getServletConfigClasses(): Array<Class<*>> {
+        return arrayOf(
+            RootConfiguration::class.java,
+            WebMvcConfiguration::class.java
+        )
+    }
+
+    override fun getServletMappings(): Array<String> {
+        return arrayOf("/")
+    }
+}
+----
+======
+
+And finally for a `web.xml` file, you configure the `DispatcherServlet` like so:
+
+[source,xml]
+----
+<listener>
+  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+</listener>
+
+<!-- All Spring Configuration (both MVC and Security) are in /WEB-INF/spring/ -->
+<context-param>
+  <param-name>contextConfigLocation</param-name>
+  <param-value>/WEB-INF/spring/*.xml</param-value>
+</context-param>
+
+<servlet>
+  <servlet-name>spring</servlet-name>
+  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+  <!-- Load from the ContextLoaderListener -->
+  <init-param>
+    <param-name>contextConfigLocation</param-name>
+    <param-value></param-value>
+  </init-param>
+</servlet>
+
+<servlet-mapping>
+  <servlet-name>spring</servlet-name>
+  <url-pattern>/</url-pattern>
+</servlet-mapping>
+----
+
+The following `WebSecurityConfiguration` in placed in the  `ApplicationContext` of the `DispatcherServlet`.
+

+ 2 - 0
web/src/main/java/org/springframework/security/web/servlet/util/matcher/MvcRequestMatcher.java

@@ -46,7 +46,9 @@ import org.springframework.web.util.UrlPathHelper;
  * @author Eddú Meléndez
  * @author Eddú Meléndez
  * @author Evgeniy Cheban
  * @author Evgeniy Cheban
  * @since 4.1.1
  * @since 4.1.1
+ * @deprecated Please use {@link PathPatternRequestMatcher} instead
  */
  */
+@Deprecated(forRemoval = true)
 public class MvcRequestMatcher implements RequestMatcher, RequestVariablesExtractor {
 public class MvcRequestMatcher implements RequestMatcher, RequestVariablesExtractor {
 
 
 	private final DefaultMatcher defaultMatcher = new DefaultMatcher();
 	private final DefaultMatcher defaultMatcher = new DefaultMatcher();