This is an automated email from the ASF dual-hosted git repository.
liuhongyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new b829f1606a fix: resolve duplicate header issue for JWT values with dot
notation (#6092)
b829f1606a is described below
commit b829f1606aad66e97fafbf834f451b8350b4f79a
Author: Jast <[email protected]>
AuthorDate: Fri Aug 8 14:14:10 2025 +0800
fix: resolve duplicate header issue for JWT values with dot notation (#6092)
---
.../jwt/strategy/DefaultJwtConvertStrategy.java | 3 +-
.../strategy/DefaultJwtConvertStrategyTest.java | 77 ++++++++++++++++++++++
2 files changed, 79 insertions(+), 1 deletion(-)
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategy.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategy.java
index 0acfb8b372..ecdf342a8e 100644
---
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategy.java
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategy.java
@@ -87,8 +87,9 @@ public class DefaultJwtConvertStrategy implements
JwtConvertStrategy {
if (converter.getJwtVal().contains(".")) {
headers.add(converter.getHeaderVal(), parse(body,
converter.getJwtVal().split("\\."), new AtomicInteger(0)));
+ } else {
+ headers.add(converter.getHeaderVal(),
String.valueOf(body.get(converter.getJwtVal())));
}
- headers.add(converter.getHeaderVal(),
String.valueOf(body.get(converter.getJwtVal())));
}
}
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategyTest.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategyTest.java
index 4a317d2bf6..e3da500be8 100644
---
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategyTest.java
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/strategy/DefaultJwtConvertStrategyTest.java
@@ -111,4 +111,81 @@ public class DefaultJwtConvertStrategyTest {
assertTrue(newExchange.getRequest().getHeaders().get("web").contains("shenyu"));
}
+ /**
+ * Test to verify the fix for the duplicate header bug.
+ * After the fix, when jwtVal contains ".", only one header should be
added with the parsed nested value.
+ */
+ @Test
+ public void testNestedJwtValueHandling() {
+ // Setup JWT body with nested structure
+ Map<String, Object> nestedJwtBody = ImmutableMap.of(
+ "user", ImmutableMap.of("name", "john", "role", "admin"),
+ "simple", "simpleValue"
+ );
+
+ // Test case 1: JWT value with dot notation (should work correctly
after fix)
+ String handleJsonWithDot =
"{\"converter\":[{\"jwtVal\":\"user.name\",\"headerVal\":\"username\"}]}";
+ DefaultJwtRuleHandle ruleHandleWithDot =
defaultJwtConvertStrategy.parseHandleJson(handleJsonWithDot);
+
+ ServerWebExchange exchangeWithDot = defaultJwtConvertStrategy
+ .convert(ruleHandleWithDot, exchange, nestedJwtBody);
+
+ // Check the headers - after fix, should only have one header value
+ var headersWithDot =
exchangeWithDot.getRequest().getHeaders().get("username");
+
+ // After fix: should only have one header value with the correct
parsed value
+ assertEquals(1, headersWithDot.size(), "After fix: Header should only
be added once");
+ assertEquals("john", headersWithDot.get(0), "Header value should be
parsed correctly from nested structure");
+
+ // Test case 2: JWT value without dot notation (should continue to
work correctly)
+ String handleJsonWithoutDot =
"{\"converter\":[{\"jwtVal\":\"simple\",\"headerVal\":\"simpleheader\"}]}";
+ DefaultJwtRuleHandle ruleHandleWithoutDot =
defaultJwtConvertStrategy.parseHandleJson(handleJsonWithoutDot);
+
+ ServerWebExchange exchangeWithoutDot = defaultJwtConvertStrategy
+ .convert(ruleHandleWithoutDot, exchange, nestedJwtBody);
+
+ var headersWithoutDot =
exchangeWithoutDot.getRequest().getHeaders().get("simpleheader");
+
+ // This should continue to work correctly - only one header value
+ assertEquals(1, headersWithoutDot.size(), "Simple values should only
add one header");
+ assertEquals("simpleValue", headersWithoutDot.get(0), "Header value
should be correct");
+ }
+
+ /**
+ * Test multiple converters with mixed dot notation and simple values.
+ */
+ @Test
+ public void testMultipleConvertersWithMixedNotation() {
+ Map<String, Object> complexJwtBody = ImmutableMap.of(
+ "user", ImmutableMap.of("name", "alice", "profile",
ImmutableMap.of("email", "[email protected]")),
+ "role", "user",
+ "permissions", ImmutableMap.of("read", true, "write", false)
+ );
+
+ String handleJson = "{\"converter\":["
+ + "{\"jwtVal\":\"user.name\",\"headerVal\":\"X-User-Name\"},"
+ + "{\"jwtVal\":\"role\",\"headerVal\":\"X-User-Role\"},"
+ +
"{\"jwtVal\":\"user.profile.email\",\"headerVal\":\"X-User-Email\"},"
+ +
"{\"jwtVal\":\"permissions.read\",\"headerVal\":\"X-Can-Read\"}"
+ + "]}";
+
+ DefaultJwtRuleHandle ruleHandle =
defaultJwtConvertStrategy.parseHandleJson(handleJson);
+ ServerWebExchange newExchange =
defaultJwtConvertStrategy.convert(ruleHandle, exchange, complexJwtBody);
+
+ // Verify all headers are added correctly
+ var headers = newExchange.getRequest().getHeaders();
+
+ assertEquals(1, headers.get("X-User-Name").size());
+ assertEquals("alice", headers.get("X-User-Name").get(0));
+
+ assertEquals(1, headers.get("X-User-Role").size());
+ assertEquals("user", headers.get("X-User-Role").get(0));
+
+ assertEquals(1, headers.get("X-User-Email").size());
+ assertEquals("[email protected]", headers.get("X-User-Email").get(0));
+
+ assertEquals(1, headers.get("X-Can-Read").size());
+ assertEquals("true", headers.get("X-Can-Read").get(0));
+ }
+
}