优化JsonMapper,增加XSS过滤通用方法

This commit is contained in:
thinkgem
2023-09-27 13:19:43 +08:00
parent dff27dc659
commit 4208223617

View File

@@ -7,13 +7,16 @@ package com.jeesite.common.mapper;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonParser.Feature; import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.util.JSONPObject; import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils; import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.io.PropertiesUtils; import com.jeesite.common.io.PropertiesUtils;
import com.jeesite.common.lang.DateUtils; import com.jeesite.common.lang.DateUtils;
@@ -31,16 +34,15 @@ import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
* 简单封装Jackson实现JSON String<->Java Object的Mapper. * 封装 Jackson实现 JSON StringJava Object 互转
* 封装不同的输出风格, 使用不同的builder函数创建实例.
* @author ThinkGem * @author ThinkGem
* @version 2016-3-2 * @version 2023-09-26
*/ */
public class JsonMapper extends ObjectMapper { public class JsonMapper extends ObjectMapper {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static Logger logger = LoggerFactory.getLogger(JsonMapper.class); private static final Logger logger = LoggerFactory.getLogger(JsonMapper.class);
/** /**
* 当前类的实例持有者(静态内部类,延迟加载,懒汉式,线程安全的单例模式) * 当前类的实例持有者(静态内部类,延迟加载,懒汉式,线程安全的单例模式)
@@ -59,9 +61,30 @@ public class JsonMapper extends ObjectMapper {
// 允许不带引号的字段名称 // 允许不带引号的字段名称
this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// 设置默认时区 // 设置默认时区
this.setDefaultTimeZone();
// 设置默认日期格式
this.setDefaultDateFormat();
// 遇到空值处理为空串
this.enabledNullValueToEmpty();
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
/**
* 开启日期类型默认格式化
* @author ThinkGem
*/
public JsonMapper setDefaultTimeZone(){
this.setTimeZone(TimeZone.getTimeZone(PropertiesUtils.getInstance() this.setTimeZone(TimeZone.getTimeZone(PropertiesUtils.getInstance()
.getProperty("lang.defaultTimeZone", "GMT+08:00"))); .getProperty("lang.defaultTimeZone", "GMT+08:00")));
// 设置默认日期格式 return this;
}
/**
* 开启日期类型默认格式化
* @author ThinkGem
*/
public JsonMapper setDefaultDateFormat(){
this.setDateFormat(new SimpleDateFormat(PropertiesUtils.getInstance() this.setDateFormat(new SimpleDateFormat(PropertiesUtils.getInstance()
.getProperty("web.json.defaultDateFormat", "yyyy-MM-dd HH:mm:ss"))); .getProperty("web.json.defaultDateFormat", "yyyy-MM-dd HH:mm:ss")));
this.setAnnotationIntrospector(new JacksonAnnotationIntrospector() { this.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
@@ -74,8 +97,7 @@ public class JsonMapper extends ObjectMapper {
if (jf != null) { if (jf != null) {
return new JsonSerializer<Date>(){ return new JsonSerializer<Date>(){
@Override @Override
public void serialize(Date value, JsonGenerator jgen, public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
SerializerProvider provider) throws IOException, JsonProcessingException {
if (value != null){ if (value != null){
jgen.writeString(DateUtils.formatDate(value, jf.pattern())); jgen.writeString(DateUtils.formatDate(value, jf.pattern()));
} }
@@ -86,27 +108,39 @@ public class JsonMapper extends ObjectMapper {
return super.findSerializer(a); return super.findSerializer(a);
} }
}); });
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性 return this;
this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); }
// 遇到空值处理为空串
/**
* 开启将空值转换为空字符串
* @author ThinkGem
*/
public JsonMapper enabledNullValueToEmpty(){
this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){ this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){
@Override @Override
public void serialize(Object value, JsonGenerator jgen, public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeString(StringUtils.EMPTY); jgen.writeString(StringUtils.EMPTY);
} }
}); });
// // 进行HTML解码先注释掉否则会造成XSS攻击比如菜单名称里输入<script>alert(123)</script>转josn后就会还原这个编码 ,并在浏览器中运行)。 return this;
// this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>(){ }
// @Override
// public void serialize(String value, JsonGenerator jgen, /**
// SerializerProvider provider) throws IOException, * 开启 XSS 过滤器
// JsonProcessingException { * @author ThinkGem
// if (value != null){ */
// jgen.writeString(StringEscapeUtils.unescapeHtml4(value)); public JsonMapper enabledXssFilter(){
// } this.registerModule(new SimpleModule().addDeserializer(String.class, new JsonDeserializer<String>() {
// } @Override
// })); public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText();
if (text != null) {
return EncodeUtils.xssFilter(text);
}
return null;
}
}));
return this;
} }
/** /**