Для проекта, над которым я работаю, я должен использовать Spring Security и JSON Webtokens, как это предусмотрено библиотекой io.jsonwebtoken (jjwt). Одно из требований, которое я должен добавить к сгенерированному токену, - это следующая сущность (упрощенная для иллюстрации проблемы):
@Entity
public class MyEntity {
private String name;
private LocalDateTime ldt;
}
Это работает, но полученный веб-токен сериализуется следующим образом:
{
"sub": "[email protected]",
"exp": 1523659655,
"entity": {
"name": testname,
"ldt": {
"hour": 0,
"minute": 37,
"dayOfMonth": 12,
"dayOfWeek": "THURSDAY",
"dayOfYear": 102,
"year": 2018,
"month": "APRIL",
"monthValue": 4,
"second": 38,
"nano": 569000000,
"chronology": {
"calendarType": "iso8601",
"id": "ISO"
}
}
}
}
Это может показаться не проблемой, но на самом деле это проблема, когда позже мне потребуется снова сопоставить ее с экземпляром MyEntity. После некоторого чтения в Интернете я решил, что мне нужно изменить конфигурацию ObjectMapper, чтобы изменить параметры конфигурации (переключить флаг WRITE_DATES_AS_TIMESTAMPS на false). Однако я не могу изменить конфигурацию ObjectMapper, используемого jjwt, поскольку он построен следующим образом (источник jjwt):
public class DefaultJwtBuilder implements JwtBuilder {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
...
}
Другой вариант, который я нашел в Интернете, заключался в том, чтобы поместить следующую строку в мой файл application.properties:
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
Но безрезультатно, ObjectMapper, используемый jjwt, похоже, игнорирует эти свойства.
Что бы я сделал для достижения своей цели?




Я исправил это, переопределив DefaultJwtBuilder, например:
public class CustomJwtBuilder extends DefaultJwtBuilder {
private static final ObjectMapper mapper = new Jackson2ObjectMapperBuilder()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.modulesToInstall(new JavaTimeModule())
.build();
@Override
protected byte[] toJson(Object object) throws JsonProcessingException {
return mapper.writeValueAsBytes(object);
}
}
А затем создав такой токен
String token = new CustomJwtBuilder()
.setSubject(..)
.setExpiration(...)
.compact();
@LesHazlewood Я принял этот ответ; когда я изначально задал вопрос, это было невозможно.
Я знаю, я сказал: «Я так понимаю, что этот ответ был дан до того, как был выпущен JJWT 0.10.0» :). Но спасибо за обновление ответа! ;)
В документации Jjwt указано, что (начиная с версии 0.10.0 и далее) вы можете внедрить свой собственный ObjectMapper с определенной зависимостью компиляции и реализовать инъекцию следующим образом:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>compile</scope> <!-- Not runtime -->
</dependency>
... затем добавьте маппер в JwtBuilder:
ObjectMapper objectMapper = getMyObjectMapper(); //implement me
String jws = Jwts.builder()
.serializeToJsonWith(new JacksonSerializer(objectMapper))
// ... etc ...
Для тех, кто задается вопросом, как реализовать getMyObjectMapper(), это зависит от того, как вы управляете внедрением зависимостей. Если вы используете простую старую Java, подойдет return new ObjectMapper(); (с желаемой конфигурацией); если вы используете Spring, возможно, этот метод возвращает экземпляр с автоматическим подключением. Это выходит за рамки этого вопроса.
Обычно это происходит, когда компилятор не может обнаружить какие-либо реализации сериализатора JSON в пути к классам. Включите следующую зависимость jjwt jackson и перестройте проект. Это решило мою проблему.
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>compile</scope>
</dependency>
Я понимаю, что этот ответ был предоставлен до того, как был выпущен JJWT 0.10.0, но после версии 0.10.0 рекомендуется использовать ответ tete на этой странице. Пользователи JJWT должны следовать этому. Ваше здоровье!