Ich implementiere einen RESTful-Webdienst, bei dem der Benutzer zusammen mit der Anfrage ein signiertes Bestätigungstoken senden muss, damit ich sicherstellen kann, dass die Anfrage nicht von einem Zwischenhändler manipuliert wurde. Meine aktuelle Implementierung ist wie folgt.
Das Verifikationstoken ist ein VerifData-Objekt, das in einen String serialisiert und dann gehasht und verschlüsselt wird.
class VerifData {
int prop1;
int prop2;
}
In meinem Dienst habe ich Daten, die serialisiert werden sollen, in eine Instanz von VerifData eingefügt und sie dann mit Jackson ObjectMapper serialisiert und zusammen mit dem Verifikationstoken an die Verifizierungs-Engine weitergeleitet.
VerfiData verifData = new VerifData(12345, 67890);
ObjectMapper mapper = new ObjectMapper();
String verifCodeGenerated = mapper.writeValueAsString(verifData);
Es scheint jedoch, dass sich bei jedem Start des Anwendungscontainers die Reihenfolge der Eigenschaften ändert, die von ObjectMapper einer Zeichenfolge zugeordnet werden.
Bsp.: Einmal wäre es
{"prop1":12345,"prop2":67890}
und ein anderes Mal wäre es
{"prop2":67890,"prop1":12345}
Wenn der Client die VerifData-Instanz als in den ersten String serialisiert hat, besteht eine 50% ige Wahrscheinlichkeit, dass sie fehlschlägt, obwohl sie korrekt ist.
Gibt es eine Möglichkeit, dies zu umgehen? Kann ich die Reihenfolge der Eigenschaften festlegen, die von ObjectMapper zugeordnet werden sollen (wie in aufsteigender Reihenfolge)? Oder gibt es eine andere Möglichkeit, diesen Überprüfungsschritt am besten umzusetzen? Sowohl Client- als auch Server-Implementierungen werden von mir entwickelt. Ich verwende die Java-Sicherheits-API zum Signieren und Überprüfen.
quelle
Die Anmerkungen sind nützlich, können aber überall schmerzhaft sein. Sie können Ihren gesamten ObjectMapper so konfigurieren, dass er auf diese Weise funktioniert
Aktuelle Jackson-Versionen:
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
Ältere Jackson-Versionen:
objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);
quelle
In Spring Boot können Sie dieses Verhalten global hinzufügen, indem Sie Ihrer
Application
Einstiegspunktklasse Folgendes hinzufügen :@Bean public Jackson2ObjectMapperBuilder objectMapperBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY); return builder; }
quelle
Es gibt einen einfacheren Weg in Spring Boot, indem Sie eine Eigenschaft angeben (
application.properties
zum Beispiel:spring.jackson.mapper.sort_properties_alphabetically=true
quelle
Verwenden Sie in Jackson 2.x, das Sie wahrscheinlich heute verwenden, Folgendes:
ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
Wenn Sie sich für das Aussehen interessieren, können Sie dies auch berücksichtigen
SerializationFeature.INDENT_OUTPUT
.Beachten Sie, dass Sie Karten oder Objekte serialisieren müssen, damit dies korrekt sortiert wird. Wenn Sie
JsonNode
beispielsweise (vonreadTree
) serialisieren , wird dies nicht richtig eingerückt.Beispiel
import com.fasterxml.jackson.databind.*; ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); mapper.configure(SerializationFeature.INDENT_OUTPUT, true); String input = "{\"hello\": {\"cruel\" : \"world\"} }"; Object pojo = mapper.readValue(input, Object.class); System.out.println(mapper.writeValueAsString(pojo));
Ergebnisse in:
{ "hello" : { "cruel" : "world" } }
quelle
Die folgenden 2 ObjectMapper-Konfigurationen sind erforderlich:
ObjectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
oder
ObjectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
und
ObjectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
oder
ObjectMapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)
Spring Boot Konfigurationsbeispiel (yaml):
spring: jackson: mapper: SORT_PROPERTIES_ALPHABETICALLY: true serialization: ORDER_MAP_ENTRIES_BY_KEYS: true
quelle
Aus Duncan McGregors Antwort: Es ist besser, es so zu verwenden:
objectMapper.configure(SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY, true);
da MapperFeature für XMLs ist und mit Jackson-Datenbindung geliefert wird, die nicht benötigt wird ...
quelle
Anstatt das Flag-Argument zu verwenden:
quelle
Sie können das Mix-In verwenden und die Reihenfolge der Eigenschaften nach Belieben festlegen:
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @Component public final class ObjectMapperUtils { private static final ObjectMapper MAPPER = new ObjectMapper(); static { MAPPER.addMixIn(Object.class, IdFirst.class); } @Bean public ObjectMapper objectMapper() { return MAPPER; } @JsonPropertyOrder({"id", "...", "..."}) private abstract static class IdFirst {} }
quelle