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:
 
-.Match by MvcRequestMatcher
+.Match by PathPatternRequestMatcher
 [tabs]
 ======
 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]]
-== 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.
 
-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]
 ======
@@ -68,70 +36,9 @@ 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("/")
-    }
-}
-----
-======
-
-[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"]
 ----
-@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
-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]]
 == @AuthenticationPrincipal
@@ -766,3 +593,95 @@ class CsrfController {
 
 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.
+
+[[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 Evgeniy Cheban
  * @since 4.1.1
+ * @deprecated Please use {@link PathPatternRequestMatcher} instead
  */
+@Deprecated(forRemoval = true)
 public class MvcRequestMatcher implements RequestMatcher, RequestVariablesExtractor {
 
 	private final DefaultMatcher defaultMatcher = new DefaultMatcher();