mirror of
https://github.com/jwtk/jjwt.git
synced 2025-03-01 18:19:04 +00:00
- Ensures that Jackson duplicate property detection/rejection is enabled by default. (#895)
Fixes #877
This commit is contained in:
parent
d878404434
commit
86e06559bc
@ -72,14 +72,8 @@ public class JacksonDeserializer<T> extends AbstractDeserializer<T> {
|
|||||||
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
|
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
|
||||||
*/
|
*/
|
||||||
public JacksonDeserializer(Map<String, Class<?>> claimTypeMap) {
|
public JacksonDeserializer(Map<String, Class<?>> claimTypeMap) {
|
||||||
// DO NOT reuse JacksonSerializer.DEFAULT_OBJECT_MAPPER as this could result in sharing the custom deserializer
|
// DO NOT specify JacksonSerializer.DEFAULT_OBJECT_MAPPER here as that would modify the shared instance
|
||||||
// between instances
|
this(JacksonSerializer.newObjectMapper(), claimTypeMap);
|
||||||
this(new ObjectMapper());
|
|
||||||
Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
|
|
||||||
// register a new Deserializer
|
|
||||||
SimpleModule module = new SimpleModule();
|
|
||||||
module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
|
|
||||||
objectMapper.registerModule(module);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,6 +86,46 @@ public class JacksonDeserializer<T> extends AbstractDeserializer<T> {
|
|||||||
this(objectMapper, (Class<T>) Object.class);
|
this(objectMapper, (Class<T>) Object.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new JacksonDeserializer where the values of the claims can be parsed into given types by registering
|
||||||
|
* a type-converting {@link com.fasterxml.jackson.databind.Module Module} on the specified {@link ObjectMapper}.
|
||||||
|
* A common usage example is to parse custom User object out of a claim, for example the claims:
|
||||||
|
* <pre>{@code
|
||||||
|
* {
|
||||||
|
* "issuer": "https://issuer.example.com",
|
||||||
|
* "user": {
|
||||||
|
* "firstName": "Jill",
|
||||||
|
* "lastName": "Coder"
|
||||||
|
* }
|
||||||
|
* }}</pre>
|
||||||
|
* Passing a map of {@code ["user": User.class]} to this constructor would result in the {@code user} claim being
|
||||||
|
* transformed to an instance of your custom {@code User} class, instead of the default of {@code Map}.
|
||||||
|
* <p>
|
||||||
|
* Because custom type parsing requires modifying the state of a Jackson {@code ObjectMapper}, this
|
||||||
|
* constructor modifies the specified {@code objectMapper} argument and customizes it to support the
|
||||||
|
* specified {@code claimTypeMap}.
|
||||||
|
* <p>
|
||||||
|
* If you do not want your {@code ObjectMapper} instance modified, but also want to support custom types for
|
||||||
|
* JWT {@code Claims}, you will need to first customize your {@code ObjectMapper} instance by registering
|
||||||
|
* your custom types separately and then use the {@link #JacksonDeserializer(ObjectMapper)} constructor instead
|
||||||
|
* (which does not modify the {@code objectMapper} argument).
|
||||||
|
*
|
||||||
|
* @param objectMapper the objectMapper to modify by registering a custom type-converting
|
||||||
|
* {@link com.fasterxml.jackson.databind.Module Module}
|
||||||
|
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
|
||||||
|
* @since 0.12.4
|
||||||
|
*/
|
||||||
|
//TODO: Make this public on a minor release
|
||||||
|
// (cannot do that on a point release as that would violate semver)
|
||||||
|
private JacksonDeserializer(ObjectMapper objectMapper, Map<String, Class<?>> claimTypeMap) {
|
||||||
|
this(objectMapper);
|
||||||
|
Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
|
||||||
|
// register a new Deserializer on the ObjectMapper instance:
|
||||||
|
SimpleModule module = new SimpleModule();
|
||||||
|
module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
|
||||||
|
objectMapper.registerModule(module);
|
||||||
|
}
|
||||||
|
|
||||||
private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) {
|
private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) {
|
||||||
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
||||||
Assert.notNull(returnType, "Return type cannot be null.");
|
Assert.notNull(returnType, "Return type cannot be null.");
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package io.jsonwebtoken.jackson.io;
|
package io.jsonwebtoken.jackson.io;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.databind.Module;
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
@ -41,7 +42,22 @@ public class JacksonSerializer<T> extends AbstractSerializer<T> {
|
|||||||
MODULE = module;
|
MODULE = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper().registerModule(MODULE);
|
static final ObjectMapper DEFAULT_OBJECT_MAPPER = newObjectMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a new ObjectMapper with the {@code jjwt-jackson} module registered and
|
||||||
|
* {@code JsonParser.Feature.STRICT_DUPLICATE_DETECTION} enabled (set to true).
|
||||||
|
*
|
||||||
|
* @return and returns a new ObjectMapper with the {@code jjwt-jackson} module registered and
|
||||||
|
* {@code JsonParser.Feature.STRICT_DUPLICATE_DETECTION} enabled (set to true).
|
||||||
|
* @since 0.12.4
|
||||||
|
*/
|
||||||
|
// package protected on purpose, do not expose to the public API
|
||||||
|
static ObjectMapper newObjectMapper() {
|
||||||
|
return new ObjectMapper()
|
||||||
|
.registerModule(MODULE)
|
||||||
|
.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); // https://github.com/jwtk/jjwt/issues/877
|
||||||
|
}
|
||||||
|
|
||||||
protected final ObjectMapper objectMapper;
|
protected final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
//file:noinspection GrDeprecatedAPIUsage
|
//file:noinspection GrDeprecatedAPIUsage
|
||||||
package io.jsonwebtoken.jackson.io
|
package io.jsonwebtoken.jackson.io
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParseException
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import io.jsonwebtoken.io.DeserializationException
|
import io.jsonwebtoken.io.DeserializationException
|
||||||
import io.jsonwebtoken.io.Deserializer
|
import io.jsonwebtoken.io.Deserializer
|
||||||
@ -120,6 +121,31 @@ class JacksonDeserializerTest {
|
|||||||
assertEquals expected, result
|
assertEquals expected, result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts https://github.com/jwtk/jjwt/issues/877
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void testStrictDuplicateDetection() {
|
||||||
|
// 'bKey' is repeated twice:
|
||||||
|
String json = """
|
||||||
|
{
|
||||||
|
"aKey":"oneValue",
|
||||||
|
"bKey": 15,
|
||||||
|
"bKey": "hello"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
try {
|
||||||
|
new JacksonDeserializer<>().deserialize(new StringReader(json))
|
||||||
|
fail()
|
||||||
|
} catch (DeserializationException expected) {
|
||||||
|
String causeMsg = "Duplicate field 'bKey'\n at [Source: (StringReader); line: 5, column: 23]"
|
||||||
|
String msg = "Unable to deserialize: $causeMsg"
|
||||||
|
assertEquals msg, expected.getMessage()
|
||||||
|
assertTrue expected.getCause() instanceof JsonParseException
|
||||||
|
assertEquals causeMsg, expected.getCause().getMessage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For: https://github.com/jwtk/jjwt/issues/564
|
* For: https://github.com/jwtk/jjwt/issues/564
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user