Skip to content

Commit 68709e8

Browse files
committed
Merge branch 'fix-swagger-index-nonce-cache' of github.com:limehee/springdoc-openapi into limehee-fix-swagger-index-nonce-cache
2 parents b50ab9c + 4720f6d commit 68709e8

3 files changed

Lines changed: 115 additions & 2 deletions

File tree

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ public final class Constants {
206206
*/
207207
public static final String INDEX_PAGE = "/index.html";
208208

209+
/**
210+
* The constant INDEX_PAGE_PATTERN.
211+
*/
212+
public static final String INDEX_PAGE_PATTERN = "/*index.html";
213+
209214
/**
210215
* The constant SWAGGER_UI_URL.
211216
*/

springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerConfigurer.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.Arrays;
1010

1111
import static org.springdoc.core.utils.Constants.ALL_PATTERN;
12+
import static org.springdoc.core.utils.Constants.INDEX_PAGE_PATTERN;
1213
import static org.springdoc.core.utils.Constants.SWAGGER_INITIALIZER_PATTERN;
1314
import static org.springdoc.core.utils.Constants.SWAGGER_UI_PREFIX;
1415
import static org.springdoc.core.utils.Constants.SWAGGER_UI_WEBJAR_NAME;
@@ -54,6 +55,7 @@ protected AbstractSwaggerConfigurer(SwaggerUiConfigProperties swaggerUiConfigPro
5455
*/
5556
protected SwaggerResourceHandlerConfig[] getSwaggerHandlerConfigs() {
5657
String swaggerUiPattern = getUiRootPath() + SWAGGER_UI_PREFIX + ALL_PATTERN;
58+
String swaggerUiIndexPattern = combinePatterns(swaggerUiPattern, INDEX_PAGE_PATTERN);
5759
String swaggerUiInitializerPattern = combinePatterns(swaggerUiPattern, SWAGGER_INITIALIZER_PATTERN);
5860
String swaggerUiResourceLocation = WEBJARS_RESOURCE_LOCATION + SWAGGER_UI_WEBJAR_NAME + DEFAULT_PATH_SEPARATOR +
5961
swaggerUiConfigProperties.getVersion() + DEFAULT_PATH_SEPARATOR;
@@ -63,7 +65,7 @@ protected SwaggerResourceHandlerConfig[] getSwaggerHandlerConfigs() {
6365
.setPatterns(swaggerUiPattern)
6466
.setLocations(swaggerUiResourceLocation),
6567
SwaggerResourceHandlerConfig.createUncached()
66-
.setPatterns(swaggerUiInitializerPattern)
68+
.setPatterns(swaggerUiIndexPattern, swaggerUiInitializerPattern)
6769
.setLocations(swaggerUiResourceLocation)
6870
};
6971
}
@@ -77,6 +79,9 @@ protected SwaggerResourceHandlerConfig[] getSwaggerWebjarHandlerConfigs() {
7779
if (!springWebProperties.getResources().isAddMappings()) return new SwaggerResourceHandlerConfig[]{};
7880

7981
String swaggerUiWebjarPattern = combinePatterns(getWebjarsPathPattern(), SWAGGER_UI_WEBJAR_NAME_PATTERN) + ALL_PATTERN;
82+
String swaggerUiWebjarIndexPattern = combinePatterns(swaggerUiWebjarPattern, INDEX_PAGE_PATTERN);
83+
String swaggerUiWebjarVersionIndexPattern = combinePatterns(swaggerUiWebjarPattern,
84+
swaggerUiConfigProperties.getVersion() + INDEX_PAGE_PATTERN);
8085
String swaggerUiWebjarInitializerPattern = combinePatterns(swaggerUiWebjarPattern, SWAGGER_INITIALIZER_PATTERN);
8186
String swaggerUiWebjarVersionInitializerPattern = combinePatterns(swaggerUiWebjarPattern,
8287
swaggerUiConfigProperties.getVersion() + SWAGGER_INITIALIZER_PATTERN);
@@ -87,7 +92,8 @@ protected SwaggerResourceHandlerConfig[] getSwaggerWebjarHandlerConfigs() {
8792
.setPatterns(swaggerUiWebjarPattern)
8893
.setLocations(swaggerUiWebjarResourceLocation),
8994
SwaggerResourceHandlerConfig.createUncached()
90-
.setPatterns(swaggerUiWebjarInitializerPattern, swaggerUiWebjarVersionInitializerPattern)
95+
.setPatterns(swaggerUiWebjarIndexPattern, swaggerUiWebjarVersionIndexPattern,
96+
swaggerUiWebjarInitializerPattern, swaggerUiWebjarVersionInitializerPattern)
9197
.setLocations(swaggerUiWebjarResourceLocation)
9298
};
9399
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
*
3+
* * Copyright 2019-2026 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.ui.app42;
20+
21+
import java.io.IOException;
22+
import java.nio.charset.StandardCharsets;
23+
24+
import jakarta.servlet.http.HttpServletRequest;
25+
import org.junit.jupiter.api.Test;
26+
import org.springdoc.core.properties.SwaggerUiConfigProperties;
27+
import org.springdoc.core.properties.SwaggerUiOAuthProperties;
28+
import org.springdoc.core.providers.ObjectMapperProvider;
29+
import org.springdoc.webmvc.ui.SwaggerIndexPageTransformer;
30+
import org.springdoc.webmvc.ui.SwaggerIndexTransformer;
31+
import org.springdoc.webmvc.ui.SwaggerWelcomeCommon;
32+
import test.org.springdoc.ui.AbstractSpringDocTest;
33+
34+
import org.springframework.boot.autoconfigure.SpringBootApplication;
35+
import org.springframework.context.annotation.Bean;
36+
import org.springframework.core.io.Resource;
37+
import org.springframework.web.servlet.resource.ResourceTransformerChain;
38+
import org.springframework.web.servlet.resource.TransformedResource;
39+
40+
import static org.hamcrest.Matchers.containsString;
41+
import static org.hamcrest.Matchers.not;
42+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
43+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
44+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
45+
46+
/**
47+
* Tests per-request Swagger UI index transformations.
48+
*
49+
* @author limehee
50+
*/
51+
public class SpringDocApp42Test extends AbstractSpringDocTest {
52+
53+
@Test
54+
void indexPageTransformerRunsForEveryRequest() throws Exception {
55+
mockMvc.perform(get("/swagger-ui/index.html").requestAttr("cspNonce", "nonce-a"))
56+
.andExpect(status().isOk())
57+
.andExpect(content().string(containsString("nonce=\"nonce-a\"")))
58+
.andExpect(content().string(not(containsString("nonce=\"nonce-b\""))));
59+
60+
mockMvc.perform(get("/swagger-ui/index.html").requestAttr("cspNonce", "nonce-b"))
61+
.andExpect(status().isOk())
62+
.andExpect(content().string(containsString("nonce=\"nonce-b\"")))
63+
.andExpect(content().string(not(containsString("nonce=\"nonce-a\""))));
64+
}
65+
66+
@SpringBootApplication
67+
static class SpringDocTestApp {
68+
69+
@Bean
70+
SwaggerIndexTransformer swaggerIndexTransformer(SwaggerUiConfigProperties swaggerUiConfig,
71+
SwaggerUiOAuthProperties swaggerUiOAuthProperties, SwaggerWelcomeCommon swaggerWelcomeCommon,
72+
ObjectMapperProvider objectMapperProvider) {
73+
return new NonceSwaggerIndexTransformer(swaggerUiConfig, swaggerUiOAuthProperties, swaggerWelcomeCommon,
74+
objectMapperProvider);
75+
}
76+
77+
}
78+
79+
static class NonceSwaggerIndexTransformer extends SwaggerIndexPageTransformer {
80+
81+
NonceSwaggerIndexTransformer(SwaggerUiConfigProperties swaggerUiConfig,
82+
SwaggerUiOAuthProperties swaggerUiOAuthProperties, SwaggerWelcomeCommon swaggerWelcomeCommon,
83+
ObjectMapperProvider objectMapperProvider) {
84+
super(swaggerUiConfig, swaggerUiOAuthProperties, swaggerWelcomeCommon, objectMapperProvider);
85+
}
86+
87+
@Override
88+
public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain)
89+
throws IOException {
90+
Resource transformedResource = super.transform(request, resource, transformerChain);
91+
if (request.getRequestURI().endsWith("/index.html")) {
92+
String html = new String(transformedResource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
93+
String nonce = request.getAttribute("cspNonce").toString();
94+
html = html.replace("<script ", "<script nonce=\"" + nonce + "\" ");
95+
return new TransformedResource(resource, html.getBytes(StandardCharsets.UTF_8));
96+
}
97+
return transformedResource;
98+
}
99+
100+
}
101+
102+
}

0 commit comments

Comments
 (0)