JSON 中所选键的掩码值
Mask value of selected key in JSON
我有 JSON 请求和响应,我想在日志中打印 JSONs,但是有一些安全字段我想避免在日志中打印,我是试图掩盖字段键:
示例:
屏蔽前:
{"username":"user1","password":"123456","country":"US","creditCardNumber":"1283-1238-0458-3458"}
屏蔽后
{"username":"user1","password":"XXXXXX","country":"US","creditCardNumber":"XXXXXX"}
我正在使用 java Gson 库,请帮我做一下
编辑
我想动态传递密钥,所以在函数 a
中我想屏蔽这些字段,但在函数 b
中不同的字段。
我认为您应该从日志中排除该字段。下面是一个使用 Gson
和 @Expose
注释的简单示例。
public static void main(String[] args) throws IOException {
String json = "{\"username\":\"user1\",\"password\":\"123456\",\"country\":\"US\",\"creditCardNumber\":\"1283-1238-0458-3458\"}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class);
System.out.println(gson.toJson(user));
Gson gsonExpose = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
System.out.println(gsonExpose.toJson(user));
}
public class User {
@Expose
private String username;
private String password;
@Expose
private String country;
private String creditCardNumber;
}
输出将是:
{"username":"user1","password":"123456","country":"US","creditCardNumber":"1283-1238-0458-3458"}
{"username":"user1","country":"US"}
另一个使用反射的解决方案:
public static void main(String[] args) throws IOException {
String json = "{\"username\":\"user1\",\"password\":\"123456\",\"country\":\"US\",\"creditCardNumber\":\"1283-1238-0458-3458\"}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class);
List<String> fieldNames = Arrays.asList("password", "creditCardNumber");
System.out.println(mask(user, fieldNames, "XXXXXXX"));
}
public static String mask(Object object, List<String> fieldNames, String mask) {
Field[] fields = object.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (fieldNames.contains(fields[i].getName())) {
try {
fields[i].setAccessible(true);
if (fields[i].get(object) != null) {
fields[i].set(object, mask);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Gson gson = new Gson();
return gson.toJson(object);
}
我喜欢上面使用反射屏蔽的解决方案,但想将其扩展到其他字段类型并保存屏蔽字段以再次取消屏蔽。
在字段顶部创建注释 @MaskedField
。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MaskedField {
}
public <T> Map<String,? super Object> maskObjectFields(T object){
Map<String,? super Object> values = new HashMap<>();
Arrays.stream(object.getClass().getDeclaredFields()).filter(field->null != field.getAnnotation(MaskedField.class)).
forEach(annotatedField->{
try {
if(annotatedField.getType().isAssignableFrom(String.class)) {
annotatedField.setAccessible(true);
values.put(annotatedField.getName(),annotatedField.get(object));
annotatedField.set(object, maskString((String) annotatedField.get(object)));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
return values;
}
public <T> void unMaskObjectFields(T object,Map values){
Arrays.stream(object.getClass().getDeclaredFields()).filter(field->null != field.getAnnotation(MaskedField.class)).
forEach(annotatedField->{
try {
annotatedField.setAccessible(true);
annotatedField.set(object,values.get(annotatedField.getName()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
}
private String maskString(String value){
if(Objects.isNull(value)) return null;
return null; //TODO: your logic goes here for masking
}
我有 JSON 请求和响应,我想在日志中打印 JSONs,但是有一些安全字段我想避免在日志中打印,我是试图掩盖字段键: 示例:
屏蔽前:
{"username":"user1","password":"123456","country":"US","creditCardNumber":"1283-1238-0458-3458"}
屏蔽后
{"username":"user1","password":"XXXXXX","country":"US","creditCardNumber":"XXXXXX"}
我正在使用 java Gson 库,请帮我做一下
编辑
我想动态传递密钥,所以在函数 a
中我想屏蔽这些字段,但在函数 b
中不同的字段。
我认为您应该从日志中排除该字段。下面是一个使用 Gson
和 @Expose
注释的简单示例。
public static void main(String[] args) throws IOException {
String json = "{\"username\":\"user1\",\"password\":\"123456\",\"country\":\"US\",\"creditCardNumber\":\"1283-1238-0458-3458\"}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class);
System.out.println(gson.toJson(user));
Gson gsonExpose = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
System.out.println(gsonExpose.toJson(user));
}
public class User {
@Expose
private String username;
private String password;
@Expose
private String country;
private String creditCardNumber;
}
输出将是:
{"username":"user1","password":"123456","country":"US","creditCardNumber":"1283-1238-0458-3458"}
{"username":"user1","country":"US"}
另一个使用反射的解决方案:
public static void main(String[] args) throws IOException {
String json = "{\"username\":\"user1\",\"password\":\"123456\",\"country\":\"US\",\"creditCardNumber\":\"1283-1238-0458-3458\"}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class);
List<String> fieldNames = Arrays.asList("password", "creditCardNumber");
System.out.println(mask(user, fieldNames, "XXXXXXX"));
}
public static String mask(Object object, List<String> fieldNames, String mask) {
Field[] fields = object.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (fieldNames.contains(fields[i].getName())) {
try {
fields[i].setAccessible(true);
if (fields[i].get(object) != null) {
fields[i].set(object, mask);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Gson gson = new Gson();
return gson.toJson(object);
}
我喜欢上面使用反射屏蔽的解决方案,但想将其扩展到其他字段类型并保存屏蔽字段以再次取消屏蔽。
在字段顶部创建注释 @MaskedField
。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MaskedField {
}
public <T> Map<String,? super Object> maskObjectFields(T object){
Map<String,? super Object> values = new HashMap<>();
Arrays.stream(object.getClass().getDeclaredFields()).filter(field->null != field.getAnnotation(MaskedField.class)).
forEach(annotatedField->{
try {
if(annotatedField.getType().isAssignableFrom(String.class)) {
annotatedField.setAccessible(true);
values.put(annotatedField.getName(),annotatedField.get(object));
annotatedField.set(object, maskString((String) annotatedField.get(object)));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
return values;
}
public <T> void unMaskObjectFields(T object,Map values){
Arrays.stream(object.getClass().getDeclaredFields()).filter(field->null != field.getAnnotation(MaskedField.class)).
forEach(annotatedField->{
try {
annotatedField.setAccessible(true);
annotatedField.set(object,values.get(annotatedField.getName()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
}
private String maskString(String value){
if(Objects.isNull(value)) return null;
return null; //TODO: your logic goes here for masking
}