2121import org .springframework .security .config .Customizer ;
2222import org .springframework .security .config .annotation .web .HttpSecurityBuilder ;
2323import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
24- import org .springframework .util .Assert ;
25- import org .springframework .web .cors .CorsConfiguration ;
2624import org .springframework .web .cors .CorsConfigurationSource ;
25+ import org .springframework .web .cors .PreFlightRequestHandler ;
2726import org .springframework .web .filter .CorsFilter ;
27+ import org .springframework .web .filter .PreFlightRequestFilter ;
2828
2929/**
30- * Adds {@link CorsFilter} to the Spring Security filter chain. If a bean by the name of
31- * corsFilter is provided, that {@link CorsFilter} is used. Else if
32- * corsConfigurationSource is defined, then that {@link CorsConfiguration} is used.
30+ * Adds {@link CorsFilter} or {@link PreFlightRequestFilter} to the Spring Security filter
31+ * chain. If a bean by the name of corsFilter is provided, that {@link CorsFilter} is
32+ * used. Else if corsConfigurationSource is defined, then that
33+ * {@link CorsConfigurationSource} is used. If a {@link PreFlightRequestHandler} is set on
34+ * this configurer, {@link CorsFilter} is not used and {@link PreFlightRequestFilter} is
35+ * registered instead.
3336 *
3437 * @param <H> the builder to return.
3538 * @author Rob Winch
@@ -43,6 +46,8 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
4346
4447 private CorsConfigurationSource configurationSource ;
4548
49+ private PreFlightRequestHandler preFlightRequestHandler ;
50+
4651 /**
4752 * Creates a new instance
4853 *
@@ -56,30 +61,85 @@ public CorsConfigurer<H> configurationSource(CorsConfigurationSource configurati
5661 return this ;
5762 }
5863
64+ /**
65+ * Use the given {@link PreFlightRequestHandler} for CORS preflight requests. When
66+ * set, {@link CorsFilter} is not used. Cannot be combined with
67+ * {@link #configurationSource(CorsConfigurationSource)}.
68+ * @param preFlightRequestHandler the handler to use
69+ * @return the {@link CorsConfigurer} for additional configuration
70+ */
71+ public CorsConfigurer <H > preFlightRequestHandler (PreFlightRequestHandler preFlightRequestHandler ) {
72+ this .preFlightRequestHandler = preFlightRequestHandler ;
73+ return this ;
74+ }
75+
5976 @ Override
6077 public void configure (H http ) {
6178 ApplicationContext context = http .getSharedObject (ApplicationContext .class );
79+
80+ if (this .configurationSource != null && this .preFlightRequestHandler != null ) {
81+ throw new IllegalStateException (
82+ "Cannot configure both a CorsConfigurationSource and a PreFlightRequestHandler on CorsConfigurer" );
83+ }
84+
6285 CorsFilter corsFilter = getCorsFilter (context );
63- Assert .state (corsFilter != null , () -> "Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "
64- + CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean." );
65- http .addFilter (corsFilter );
86+ if (corsFilter != null ) {
87+ http .addFilter (corsFilter );
88+ return ;
89+ }
90+ PreFlightRequestHandler preFlightRequestHandlerBean = getPreFlightRequestHandler (context );
91+ if (preFlightRequestHandlerBean != null ) {
92+ http .addFilterBefore (new PreFlightRequestFilter (preFlightRequestHandlerBean ), CorsFilter .class );
93+ return ;
94+ }
95+ throw new NoSuchBeanDefinitionException (CorsConfigurationSource .class ,
96+ "Failed to find a bean that implements `CorsConfigurationSource`. Please ensure that you are using "
97+ + "`@EnableWebMvc`, are publishing a `WebMvcConfigurer`, or are publishing a `CorsConfigurationSource` bean." );
98+ }
99+
100+ private PreFlightRequestHandler getPreFlightRequestHandler (ApplicationContext context ) {
101+ if (this .configurationSource != null ) {
102+ return null ;
103+ }
104+ if (this .preFlightRequestHandler != null ) {
105+ return this .preFlightRequestHandler ;
106+ }
107+ if (context == null ) {
108+ return null ;
109+ }
110+ if (context .getBeanNamesForType (PreFlightRequestHandler .class ).length > 0 ) {
111+ return context .getBean (PreFlightRequestHandler .class );
112+ }
113+ return null ;
114+ }
115+
116+ private CorsConfigurationSource getCorsConfigurationSource (ApplicationContext context ) {
117+ if (context == null ) {
118+ return null ;
119+ }
120+ boolean containsCorsSource = context .containsBeanDefinition (CORS_CONFIGURATION_SOURCE_BEAN_NAME );
121+ if (containsCorsSource ) {
122+ return context .getBean (CORS_CONFIGURATION_SOURCE_BEAN_NAME , CorsConfigurationSource .class );
123+ }
124+ return MvcCorsFilter .getMvcCorsConfigurationSource (context );
66125 }
67126
68127 private CorsFilter getCorsFilter (ApplicationContext context ) {
128+ if (this .preFlightRequestHandler != null ) {
129+ return null ;
130+ }
69131 if (this .configurationSource != null ) {
70132 return new CorsFilter (this .configurationSource );
71133 }
72- boolean containsCorsFilter = context .containsBeanDefinition (CORS_FILTER_BEAN_NAME );
134+ boolean containsCorsFilter = context != null && context .containsBeanDefinition (CORS_FILTER_BEAN_NAME );
73135 if (containsCorsFilter ) {
74136 return context .getBean (CORS_FILTER_BEAN_NAME , CorsFilter .class );
75137 }
76- boolean containsCorsSource = context .containsBean (CORS_CONFIGURATION_SOURCE_BEAN_NAME );
77- if (containsCorsSource ) {
78- CorsConfigurationSource configurationSource = context .getBean (CORS_CONFIGURATION_SOURCE_BEAN_NAME ,
79- CorsConfigurationSource .class );
80- return new CorsFilter (configurationSource );
138+ CorsConfigurationSource corsConfigurationSource = getCorsConfigurationSource (context );
139+ if (corsConfigurationSource != null ) {
140+ return new CorsFilter (corsConfigurationSource );
81141 }
82- return MvcCorsFilter . getMvcCorsFilter ( context ) ;
142+ return null ;
83143 }
84144
85145 static class MvcCorsFilter {
@@ -92,15 +152,11 @@ static class MvcCorsFilter {
92152 * @param context
93153 * @return
94154 */
95- private static CorsFilter getMvcCorsFilter (ApplicationContext context ) {
155+ private static CorsConfigurationSource getMvcCorsConfigurationSource (ApplicationContext context ) {
96156 if (context .containsBean (HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME )) {
97- CorsConfigurationSource corsConfigurationSource = context
98- .getBean (HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME , CorsConfigurationSource .class );
99- return new CorsFilter (corsConfigurationSource );
157+ return context .getBean (HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME , CorsConfigurationSource .class );
100158 }
101- throw new NoSuchBeanDefinitionException (CorsConfigurationSource .class ,
102- "Failed to find a bean that implements `CorsConfigurationSource`. Please ensure that you are using "
103- + "`@EnableWebMvc`, are publishing a `WebMvcConfigurer`, or are publishing a `CorsConfigurationSource` bean." );
159+ return null ;
104160 }
105161
106162 }
0 commit comments