spring MVC 对 ResponseBody返回json数据进行脱敏处理 spring MVCResponseBodySensitive
程序员文章站
2022-04-07 21:18:17
...
为了对springmvc框架中的json请求数据进行可控制的脱敏处理,研究了配置message-converters里面的内容,并通过重写部分方法进行脱敏修改
- 配置message-converters
<mvc:annotation-driven> <!-- 处理responseBody 返回结果 --> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <!--<bean class="com.fasterxml.jackson.databind.ObjectMapper">--> <bean class="com.ez.core.servlet.SensitiveObjectMapper"> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" /> </bean> </property> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
- 需要重写的类有 “com.fasterxml.jackson.databind.ObjectMapper”, “com.fasterxml.jackson.databind.MappingJsonFactory”,“com.fasterxml.jackson.core.json.UTF8JsonGenerator”;
package com.ez.core.servlet; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext; import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider; /** * Created by Administrator on 2018/2/8. */ public class SensitiveObjectMapper extends ObjectMapper { /** * 对弗雷的jsonfactory使用自定义工厂 */ public SensitiveObjectMapper() { super(new SensitiveJsonFactory(), (DefaultSerializerProvider) null, (DefaultDeserializationContext) null); } }
package com.ez.core.servlet; import com.fasterxml.jackson.core.JsonEncoding; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.SerializableString; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.json.UTF8JsonGenerator; import com.fasterxml.jackson.databind.MappingJsonFactory; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; /** * Created by Administrator on 2018/2/8. */ public class SensitiveJsonFactory extends MappingJsonFactory { public SensitiveJsonFactory() { super(); } public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { IOContext ctxt = this._createContext(out, false); ctxt.setEncoding(enc); if (enc == JsonEncoding.UTF8) { return this._createUTF8Generator(this._decorate(out, ctxt), ctxt); } else { Writer w = this._createWriter(out, enc, ctxt); return this._createGenerator(this._decorate(w, ctxt), ctxt); } } /** * 主要是重写该方法,对需要进行脱敏处理的数据,使用 SensitiveUTF8JsonGenerator 处理, * 不需要脱敏的数据,还是按照原来的路径进行处理 * @param out * @param ctxt * @return * @throws IOException */ protected JsonGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) throws IOException { UTF8JsonGenerator gen = null; boolean needSensitive = !true; if (needSensitive) { gen = new SensitiveUTF8JsonGenerator(ctxt, this._generatorFeatures, this._objectCodec, out); } else { gen = new UTF8JsonGenerator(ctxt, this._generatorFeatures, this._objectCodec, out); } if (this._characterEscapes != null) { gen.setCharacterEscapes(this._characterEscapes); } SerializableString rootSep = this._rootValueSeparator; // if (rootSep != _rootValueSeparator) { // if(rootSep != DEFAULT_ROOT_VALUE_SEPARATOR) { gen.setRootValueSeparator(rootSep); // } return gen; } }
最后需要对真正写入流的方法进行重写,通过判断是否需要进行脱敏处理,然后根据具体的脱敏规则进行处理,判断时可能需要通过当前数据的路径进行判断,所以增加了basePath存储先关路径,一般脱敏规则,是将相关数据替换为***
package com.ez.core.servlet; import com.fasterxml.jackson.core.Base64Variant; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.core.SerializableString; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.json.UTF8JsonGenerator; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.math.BigDecimal; import java.math.BigInteger; /** * Created by Administrator on 2018/2/8. */ public class SensitiveUTF8JsonGenerator extends UTF8JsonGenerator { private StringBuffer basePath = new StringBuffer(); // private String[] path = new String[]; public SensitiveUTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out) { super(ctxt, features, codec, out); } public SensitiveUTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out, byte[] outputBuffer, int outputOffset, boolean bufferRecyclable) { super(ctxt, features, codec, out, outputBuffer, outputOffset, bufferRecyclable); } private void addPath(SerializableString name) { this.basePath.append(".").append(name); } private void addPath(String name) { this.basePath.append(".").append(name); } private void deleteOnePath() { int index = basePath.lastIndexOf("."); if (index != -1) { basePath.delete(index, basePath.length()); } } private void dealRemovePath() { deleteOnePath(); } public void writeFieldName(SerializableString name) throws IOException { addPath(name); super.writeFieldName(name); } public void writeFieldName(String name) throws IOException { addPath(name); super.writeFieldName(name); } public void writeString(String text) throws IOException { text = sensitiveTransfer(text); super.writeString(text); } public void writeString(Reader reader, int len) throws IOException { super.writeString(reader, len); dealRemovePath(); } public void writeString(char[] text, int offset, int len) throws IOException { super.writeString(text, offset, len); dealRemovePath(); } public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException { super.writeRawUTF8String(text, offset, length); dealRemovePath(); } public void writeUTF8String(byte[] text, int offset, int len) throws IOException { super.writeUTF8String(text, offset, len); dealRemovePath(); } public void writeBinary(Base64Variant a, byte[] b, int c, int d) throws IOException, JsonGenerationException { super.writeBinary(a, b, c, d); dealRemovePath(); } public int writeBinary(Base64Variant a, InputStream b, int c) throws IOException, JsonGenerationException { int ret = super.writeBinary(a, b, c); dealRemovePath(); return ret; } public void writeNumber(short s) throws IOException { super.writeNumber(s); sensitiveTransfer(s); } private void sensitiveTransfer(short s) { sensitiveTransfer(s); } public void writeNumber(int i) throws IOException { super.writeNumber(i); sensitiveTransfer(i); } private void sensitiveTransfer(int i) { dealRemovePath(); } public void writeNumber(long l) throws IOException { super.writeNumber(l); sensitiveTransfer(l); } private void sensitiveTransfer(long l) { dealRemovePath(); } public void writeNumber(BigInteger value) throws IOException { super.writeNumber(value); sensitiveTransfer(value); } private void sensitiveTransfer(BigInteger value) { dealRemovePath(); } public void writeNumber(double d) throws IOException { super.writeNumber(d); sensitiveTransfer(d); } private void sensitiveTransfer(double d) { dealRemovePath(); } public void writeNumber(float f) throws IOException { super.writeNumber(f); sensitiveTransfer(f); } private void sensitiveTransfer(float f) { dealRemovePath(); } public void writeNumber(BigDecimal value) throws IOException { super.writeNumber(value); sensitiveTransfer(value); } private void sensitiveTransfer(BigDecimal value) { dealRemovePath(); } public void writeNumber(String encodedValue) throws IOException { encodedValue = sensitiveTransfer(encodedValue); super.writeNumber(encodedValue); } private String sensitiveTransfer(String encodedValue) { /** * 判断是否需要进行脱敏 * 根据 basePath 和脱敏规则; */ // String ret = encodedValue ; String ret = encodedValue + "脱敏"; // System.out.println("basePath: " + basePath); // try { // System.out.println(new String(this._outputBuffer, "UTF-8")); // } catch (UnsupportedEncodingException e) { // e.printStackTrace(); // } dealRemovePath(); return ret; } public void writeBoolean(boolean state) throws IOException { super.writeBoolean(state); sensitiveTransfer(state); } private void sensitiveTransfer(boolean state) { /** * 判断是否需要进行脱敏 * 根据 basePath 和脱敏规则; */ dealRemovePath(); } public void writeNull() throws IOException { super.writeNull(); dealRemovePath(); } }