在项目中出现License签名验证失败的问题,根本原因是YudaoJacksonAutoConfiguration中配置的全局LocalDateTime序列化器与LicenseGenerator中的序列化配置不一致,导致时间字段在签名数据生成时格式不同。
在YudaoJacksonAutoConfiguration中配置了全局的LocalDateTime序列化器:
// 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
TimestampLocalDateTimeSerializer将LocalDateTime序列化为时间戳:
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// 将 LocalDateTime 对象,转换为 Long 时间戳
gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
}
LicenseGenerator使用标准的Jackson配置:
public LicenseGenerator() {
this.objectMapper = new ObjectMapper();
this.objectMapper.registerModule(new JavaTimeModule());
this.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 禁用时间戳格式
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
}
2024-01-15T10:30:00)LocalDateTime被序列化为时间戳(如:1705294200000)这导致签名数据字符串不同,进而导致签名验证失败。
修改LicenseGenerator的构造函数,使其与项目保持一致:
public LicenseGenerator() {
this.objectMapper = new ObjectMapper();
this.objectMapper.registerModule(new JavaTimeModule());
// 使用与项目一致的LocalDateTime序列化配置
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE);
simpleModule.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
this.objectMapper.registerModule(simpleModule);
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
}
为License验证创建独立的ObjectMapper,不受全局配置影响:
private static ObjectMapper createLicenseObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
在createSignatureData方法中,对时间字段进行特殊处理,确保格式一致:
private void appendField(StringBuilder sb, String fieldName, Object value) {
sb.append(fieldName).append("=");
if (value != null) {
if (value instanceof LocalDateTime) {
// 统一使用时间戳格式
LocalDateTime dateTime = (LocalDateTime) value;
long timestamp = dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
sb.append(timestamp);
} else {
sb.append(value.toString());
}
}
sb.append(";");
}
LicenseGenerator使其与项目配置保持一致LicenseGenerator重新生成所有License文件