1
1
/*
2
- * Copyright 2012-2024 the original author or authors.
2
+ * Copyright 2012-2025 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
40
40
import org .springframework .context .ApplicationContext ;
41
41
import org .springframework .core .annotation .MergedAnnotation ;
42
42
import org .springframework .core .annotation .MergedAnnotations ;
43
+ import org .springframework .http .HttpMethod ;
43
44
import org .springframework .security .web .server .util .matcher .OrServerWebExchangeMatcher ;
44
45
import org .springframework .security .web .server .util .matcher .PathPatternParserServerWebExchangeMatcher ;
45
46
import org .springframework .security .web .server .util .matcher .ServerWebExchangeMatcher ;
56
57
*
57
58
* @author Madhura Bhave
58
59
* @author Phillip Webb
60
+ * @author Chris Bono
59
61
* @since 2.0.0
60
62
*/
61
63
public final class EndpointRequest {
@@ -180,12 +182,14 @@ private ServerWebExchangeMatcher createDelegate(Supplier<C> context) {
180
182
181
183
protected abstract ServerWebExchangeMatcher createDelegate (C context );
182
184
183
- protected final List <ServerWebExchangeMatcher > getDelegateMatchers (Set <String > paths ) {
184
- return paths .stream ().map (this ::getDelegateMatcher ).collect (Collectors .toCollection (ArrayList ::new ));
185
+ protected final List <ServerWebExchangeMatcher > getDelegateMatchers (Set <String > paths , HttpMethod httpMethod ) {
186
+ return paths .stream ()
187
+ .map ((path ) -> getDelegateMatcher (path , httpMethod ))
188
+ .collect (Collectors .toCollection (ArrayList ::new ));
185
189
}
186
190
187
- private PathPatternParserServerWebExchangeMatcher getDelegateMatcher (String path ) {
188
- return new PathPatternParserServerWebExchangeMatcher (path + "/**" );
191
+ private PathPatternParserServerWebExchangeMatcher getDelegateMatcher (String path , HttpMethod httpMethod ) {
192
+ return new PathPatternParserServerWebExchangeMatcher (path + "/**" , httpMethod );
189
193
}
190
194
191
195
@ Override
@@ -258,39 +262,53 @@ public static final class EndpointServerWebExchangeMatcher extends AbstractWebEx
258
262
259
263
private final boolean includeLinks ;
260
264
265
+ private final HttpMethod httpMethod ;
266
+
261
267
private EndpointServerWebExchangeMatcher (boolean includeLinks ) {
262
- this (Collections .emptyList (), Collections .emptyList (), includeLinks );
268
+ this (Collections .emptyList (), Collections .emptyList (), includeLinks , null );
263
269
}
264
270
265
271
private EndpointServerWebExchangeMatcher (Class <?>[] endpoints , boolean includeLinks ) {
266
- this (Arrays .asList ((Object []) endpoints ), Collections .emptyList (), includeLinks );
272
+ this (Arrays .asList ((Object []) endpoints ), Collections .emptyList (), includeLinks , null );
267
273
}
268
274
269
275
private EndpointServerWebExchangeMatcher (String [] endpoints , boolean includeLinks ) {
270
- this (Arrays .asList ((Object []) endpoints ), Collections .emptyList (), includeLinks );
276
+ this (Arrays .asList ((Object []) endpoints ), Collections .emptyList (), includeLinks , null );
271
277
}
272
278
273
- private EndpointServerWebExchangeMatcher (List <Object > includes , List <Object > excludes , boolean includeLinks ) {
279
+ private EndpointServerWebExchangeMatcher (List <Object > includes , List <Object > excludes , boolean includeLinks ,
280
+ HttpMethod httpMethod ) {
274
281
super (PathMappedEndpoints .class );
275
282
this .includes = includes ;
276
283
this .excludes = excludes ;
277
284
this .includeLinks = includeLinks ;
285
+ this .httpMethod = httpMethod ;
278
286
}
279
287
280
288
public EndpointServerWebExchangeMatcher excluding (Class <?>... endpoints ) {
281
289
List <Object > excludes = new ArrayList <>(this .excludes );
282
290
excludes .addAll (Arrays .asList ((Object []) endpoints ));
283
- return new EndpointServerWebExchangeMatcher (this .includes , excludes , this .includeLinks );
291
+ return new EndpointServerWebExchangeMatcher (this .includes , excludes , this .includeLinks , null );
284
292
}
285
293
286
294
public EndpointServerWebExchangeMatcher excluding (String ... endpoints ) {
287
295
List <Object > excludes = new ArrayList <>(this .excludes );
288
296
excludes .addAll (Arrays .asList ((Object []) endpoints ));
289
- return new EndpointServerWebExchangeMatcher (this .includes , excludes , this .includeLinks );
297
+ return new EndpointServerWebExchangeMatcher (this .includes , excludes , this .includeLinks , null );
290
298
}
291
299
292
300
public EndpointServerWebExchangeMatcher excludingLinks () {
293
- return new EndpointServerWebExchangeMatcher (this .includes , this .excludes , false );
301
+ return new EndpointServerWebExchangeMatcher (this .includes , this .excludes , false , null );
302
+ }
303
+
304
+ /**
305
+ * Restricts the matcher to only consider requests with a particular http method.
306
+ * @param httpMethod the http method to include
307
+ * @return a copy of the matcher further restricted to only match requests with
308
+ * the specified http method
309
+ */
310
+ public EndpointServerWebExchangeMatcher withHttpMethod (HttpMethod httpMethod ) {
311
+ return new EndpointServerWebExchangeMatcher (this .includes , this .excludes , this .includeLinks , httpMethod );
294
312
}
295
313
296
314
@ Override
@@ -301,7 +319,7 @@ protected ServerWebExchangeMatcher createDelegate(PathMappedEndpoints endpoints)
301
319
}
302
320
streamPaths (this .includes , endpoints ).forEach (paths ::add );
303
321
streamPaths (this .excludes , endpoints ).forEach (paths ::remove );
304
- List <ServerWebExchangeMatcher > delegateMatchers = getDelegateMatchers (paths );
322
+ List <ServerWebExchangeMatcher > delegateMatchers = getDelegateMatchers (paths , this . httpMethod );
305
323
if (this .includeLinks && StringUtils .hasText (endpoints .getBasePath ())) {
306
324
delegateMatchers .add (new LinksServerWebExchangeMatcher ());
307
325
}
@@ -357,22 +375,37 @@ public static class AdditionalPathsEndpointServerWebExchangeMatcher
357
375
358
376
private final List <Object > endpoints ;
359
377
378
+ private final HttpMethod httpMethod ;
379
+
360
380
AdditionalPathsEndpointServerWebExchangeMatcher (WebServerNamespace webServerNamespace , String ... endpoints ) {
361
- this (webServerNamespace , Arrays .asList ((Object []) endpoints ));
381
+ this (webServerNamespace , Arrays .asList ((Object []) endpoints ), null );
362
382
}
363
383
364
384
AdditionalPathsEndpointServerWebExchangeMatcher (WebServerNamespace webServerNamespace , Class <?>... endpoints ) {
365
- this (webServerNamespace , Arrays .asList ((Object []) endpoints ));
385
+ this (webServerNamespace , Arrays .asList ((Object []) endpoints ), null );
366
386
}
367
387
368
388
private AdditionalPathsEndpointServerWebExchangeMatcher (WebServerNamespace webServerNamespace ,
369
- List <Object > endpoints ) {
389
+ List <Object > endpoints , HttpMethod httpMethod ) {
370
390
super (PathMappedEndpoints .class );
371
391
Assert .notNull (webServerNamespace , "'webServerNamespace' must not be null" );
372
392
Assert .notNull (endpoints , "'endpoints' must not be null" );
373
393
Assert .notEmpty (endpoints , "'endpoints' must not be empty" );
374
394
this .webServerNamespace = webServerNamespace ;
375
395
this .endpoints = endpoints ;
396
+ this .httpMethod = httpMethod ;
397
+ }
398
+
399
+ /**
400
+ * Restricts the matcher to only consider requests with a particular HTTP method.
401
+ * @param httpMethod the HTTP method to include
402
+ * @return a copy of the matcher further restricted to only match requests with
403
+ * the specified HTTP method
404
+ * @since 3.5.0
405
+ */
406
+ public AdditionalPathsEndpointServerWebExchangeMatcher withHttpMethod (HttpMethod httpMethod ) {
407
+ return new AdditionalPathsEndpointServerWebExchangeMatcher (this .webServerNamespace , this .endpoints ,
408
+ httpMethod );
376
409
}
377
410
378
411
@ Override
@@ -388,7 +421,7 @@ protected ServerWebExchangeMatcher createDelegate(PathMappedEndpoints endpoints)
388
421
.map (this ::getEndpointId )
389
422
.flatMap ((endpointId ) -> streamAdditionalPaths (endpoints , endpointId ))
390
423
.collect (Collectors .toCollection (LinkedHashSet ::new ));
391
- List <ServerWebExchangeMatcher > delegateMatchers = getDelegateMatchers (paths );
424
+ List <ServerWebExchangeMatcher > delegateMatchers = getDelegateMatchers (paths , this . httpMethod );
392
425
return (!CollectionUtils .isEmpty (delegateMatchers )) ? new OrServerWebExchangeMatcher (delegateMatchers )
393
426
: EMPTY_MATCHER ;
394
427
}
0 commit comments