Skip to content

Commit 362e2f9

Browse files
committed
Support per method security requirement in RepositoryRestResource. Fixes #1059
1 parent ea31a59 commit 362e2f9

File tree

7 files changed

+133
-24
lines changed

7 files changed

+133
-24
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/core/SecurityService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public io.swagger.v3.oas.annotations.security.SecurityRequirement[] getSecurityR
135135
* @param allSecurityTags the all security tags
136136
* @return the security requirements for method
137137
*/
138-
private Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> getSecurityRequirementsForMethod(Method method, Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> allSecurityTags) {
138+
public Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> getSecurityRequirementsForMethod(Method method, Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> allSecurityTags) {
139139
io.swagger.v3.oas.annotations.security.SecurityRequirements methodSecurity = AnnotatedElementUtils.findMergedAnnotation(method, io.swagger.v3.oas.annotations.security.SecurityRequirements.class);
140140
if (methodSecurity != null)
141141
allSecurityTags = addSecurityRequirements(allSecurityTags, new HashSet<>(Arrays.asList(methodSecurity.value())));

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestOperationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ private Operation buildSearchOperation(HandlerMethod handlerMethod, DataRestRepo
225225
.ifPresent(methodParameterPage -> dataRestRequestService.buildCommonParameters(domainType, openAPI, requestMethod, methodAttributes, operation, new String[] { methodParameterPage.getParameterName() }, new MethodParameter[] { methodParameterPage }));
226226
}
227227
dataRestResponseService.buildSearchResponse(operation, handlerMethod, openAPI, methodResourceMapping, domainType, methodAttributes);
228-
tagsBuilder.buildSearchTags(operation, handlerMethod, dataRestRepository);
228+
tagsBuilder.buildSearchTags(operation, handlerMethod, dataRestRepository, method);
229229
return operation;
230230
}
231231

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/core/DataRestTagsService.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
package org.springdoc.data.rest.core;
2525

26+
import java.lang.reflect.Method;
2627
import java.util.HashSet;
2728
import java.util.Set;
2829

@@ -65,8 +66,8 @@ public DataRestTagsService(OpenAPIService openAPIService) {
6566
* @param dataRestRepository the repository data rest
6667
*/
6768
public void buildSearchTags(Operation operation, HandlerMethod handlerMethod,
68-
DataRestRepository dataRestRepository) {
69-
buildTags(operation, handlerMethod, dataRestRepository);
69+
DataRestRepository dataRestRepository, Method method) {
70+
buildTags(operation, handlerMethod, dataRestRepository, method);
7071
}
7172

7273
/**
@@ -78,18 +79,18 @@ public void buildSearchTags(Operation operation, HandlerMethod handlerMethod,
7879
*/
7980
public void buildEntityTags(Operation operation, HandlerMethod handlerMethod,
8081
DataRestRepository dataRestRepository) {
81-
buildTags(operation, handlerMethod, dataRestRepository);
82+
buildTags(operation, handlerMethod, dataRestRepository, null);
8283
}
8384

8485
/**
8586
* Build tags.
86-
*
87-
* @param operation the operation
87+
* @param operation the operation
8888
* @param handlerMethod the handler method
8989
* @param dataRestRepository the repository data rest
90+
* @param method
9091
*/
9192
private void buildTags(Operation operation, HandlerMethod handlerMethod,
92-
DataRestRepository dataRestRepository) {
93+
DataRestRepository dataRestRepository, Method method) {
9394
String tagName = handlerMethod.getBeanType().getSimpleName();
9495
if (SpringRepositoryRestResourceProvider.REPOSITORY_SCHEMA_CONTROLLER.equals(handlerMethod.getBeanType().getName())
9596
|| AlpsController.class.equals(handlerMethod.getBeanType())
@@ -111,6 +112,8 @@ else if (dataRestRepository != null && dataRestRepository.getDomainType() != nul
111112
}
112113
final SecurityService securityParser = openAPIService.getSecurityParser();
113114
Set<io.swagger.v3.oas.annotations.security.SecurityRequirement> allSecurityTags = securityParser.getSecurityRequirementsForClass(repositoryType);
115+
if (method != null)
116+
allSecurityTags = securityParser.getSecurityRequirementsForMethod(method, allSecurityTags);
114117
if (!CollectionUtils.isEmpty(allSecurityTags))
115118
securityParser.buildSecurityRequirement(allSecurityTags.toArray(new io.swagger.v3.oas.annotations.security.SecurityRequirement[0]), operation);
116119
}

springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app16/CustomerRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
package test.org.springdoc.api.app16;
2525

26+
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
2627
import io.swagger.v3.oas.annotations.tags.Tag;
2728

2829
import org.springframework.data.domain.Page;
@@ -49,6 +50,7 @@ public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaS
4950
* @param pageable
5051
* @return
5152
*/
53+
@SecurityRequirement(name = "bearer")
5254
Page<Customer> findByLastname(@Param("lastname") String lastname, Pageable pageable);
5355

5456
@Override

springdoc-openapi-data-rest/src/test/resources/results/app16.json

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,12 @@
696696
"404": {
697697
"description": "Not Found"
698698
}
699-
}
699+
},
700+
"security": [
701+
{
702+
"bearer": []
703+
}
704+
]
700705
}
701706
},
702707
"/customers/{id}": {
@@ -1004,21 +1009,6 @@
10041009
}
10051010
}
10061011
},
1007-
"Customer": {
1008-
"type": "object",
1009-
"properties": {
1010-
"id": {
1011-
"type": "integer",
1012-
"format": "int64"
1013-
},
1014-
"firstname": {
1015-
"type": "string"
1016-
},
1017-
"lastname": {
1018-
"type": "string"
1019-
}
1020-
}
1021-
},
10221012
"CollectionModelAccount": {
10231013
"type": "object",
10241014
"properties": {
@@ -1038,6 +1028,21 @@
10381028
}
10391029
}
10401030
},
1031+
"Customer": {
1032+
"type": "object",
1033+
"properties": {
1034+
"id": {
1035+
"type": "integer",
1036+
"format": "int64"
1037+
},
1038+
"firstname": {
1039+
"type": "string"
1040+
},
1041+
"lastname": {
1042+
"type": "string"
1043+
}
1044+
}
1045+
},
10411046
"RepresentationModelAccount": {
10421047
"type": "object",
10431048
"properties": {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
*
3+
* *
4+
* * * Copyright 2019-2020 the original author or authors.
5+
* * *
6+
* * * Licensed under the Apache License, Version 2.0 (the "License");
7+
* * * you may not use this file except in compliance with the License.
8+
* * * You may obtain a copy of the License at
9+
* * *
10+
* * * https://www.apache.org/licenses/LICENSE-2.0
11+
* * *
12+
* * * Unless required by applicable law or agreed to in writing, software
13+
* * * distributed under the License is distributed on an "AS IS" BASIS,
14+
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* * * See the License for the specific language governing permissions and
16+
* * * limitations under the License.
17+
* *
18+
*
19+
*/
20+
21+
package test.org.springdoc.api.app151;
22+
23+
import java.util.function.Consumer;
24+
import java.util.function.Supplier;
25+
26+
import org.springdoc.core.fn.builders.operation.Builder;
27+
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
28+
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.web.reactive.function.server.RequestPredicates;
32+
import org.springframework.web.reactive.function.server.RouterFunction;
33+
import org.springframework.web.reactive.function.server.RouterFunctions;
34+
import org.springframework.web.reactive.function.server.ServerResponse;
35+
36+
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
37+
import static org.springframework.web.reactive.function.server.RouterFunctions.nest;
38+
import static test.org.springdoc.api.AbstractSpringDocTest.HANDLER_FUNCTION;
39+
40+
@Configuration
41+
public class HelloRouter {
42+
43+
@Bean
44+
RouterFunction<?> routeSample() {
45+
Supplier<RouterFunction<ServerResponse>> routerFunctionSupplier =
46+
() -> SpringdocRouteBuilder.route()
47+
.GET("toto", HANDLER_FUNCTION, builder -> builder.operationId("get-user-groups"))
48+
49+
.POST("/titi", HANDLER_FUNCTION, builder -> builder.operationId("create-user-group-special")).build();
50+
51+
Consumer<Builder> operationsConsumer = builder -> { };
52+
53+
return RouterFunctions.nest(RequestPredicates.path("/users"), nest(path("/test"), nest(path("/greeter"),
54+
SpringdocRouteBuilder.route()
55+
.GET("", HANDLER_FUNCTION, builder -> builder.operationId("get-users"))
56+
.POST("/special", HANDLER_FUNCTION, builder -> builder.operationId("create-user-special"))
57+
.nest(path("/groups"), routerFunctionSupplier, operationsConsumer)
58+
.nest(path("/groups2"), routerFunctionSupplier, operationsConsumer)
59+
.nest(path("/greeter3").or(path("/greeter4")), routerFunctionSupplier, operationsConsumer)
60+
.build())));
61+
62+
}
63+
64+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
*
3+
* *
4+
* * * Copyright 2019-2020 the original author or authors.
5+
* * *
6+
* * * Licensed under the Apache License, Version 2.0 (the "License");
7+
* * * you may not use this file except in compliance with the License.
8+
* * * You may obtain a copy of the License at
9+
* * *
10+
* * * https://www.apache.org/licenses/LICENSE-2.0
11+
* * *
12+
* * * Unless required by applicable law or agreed to in writing, software
13+
* * * distributed under the License is distributed on an "AS IS" BASIS,
14+
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* * * See the License for the specific language governing permissions and
16+
* * * limitations under the License.
17+
* *
18+
*
19+
*/
20+
21+
package test.org.springdoc.api.app151;
22+
23+
import test.org.springdoc.api.AbstractSpringDocTest;
24+
25+
import org.springframework.boot.autoconfigure.SpringBootApplication;
26+
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
27+
import org.springframework.context.annotation.ComponentScan;
28+
29+
@AutoConfigureWebTestClient(timeout = "3600000")
30+
public class SpringDocApp150Test extends AbstractSpringDocTest {
31+
32+
@SpringBootApplication
33+
@ComponentScan(basePackages = { "org.springdoc", "test.org.springdoc.api.app150" })
34+
static class SpringDocTestApp {}
35+
}

0 commit comments

Comments
 (0)