操作日志参数过滤&脱敏.

This commit is contained in:
lijiahang
2023-10-12 12:59:56 +08:00
parent 1571d47bfb
commit b1e1a87089
16 changed files with 165 additions and 50 deletions

View File

@@ -0,0 +1,43 @@
package com.orion.ops.framework.common.json.filter;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.orion.lang.utils.Desensitizes;
import com.orion.lang.utils.Objects1;
import com.orion.lang.utils.collect.Lists;
import java.util.List;
/**
* 字段脱敏过滤器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/10/12 11:34
*/
public class FieldDesensitizeFilter implements ValueFilter {
private final int keepStart;
private final int keepEnd;
private final List<String> desensitizeFields;
public FieldDesensitizeFilter(List<String> desensitizeFields) {
this(1, 1, desensitizeFields);
}
public FieldDesensitizeFilter(int keepStart, int keepEnd, List<String> desensitizeFields) {
this.keepStart = keepStart;
this.keepEnd = keepEnd;
this.desensitizeFields = desensitizeFields;
}
@Override
public Object process(Object object, String name, Object value) {
if (Lists.isEmpty(desensitizeFields) || !desensitizeFields.contains(name)) {
return value;
}
return Desensitizes.mix(Objects1.toString(value), keepStart, keepEnd);
}
}

View File

@@ -0,0 +1,28 @@
package com.orion.ops.framework.common.json.filter;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.orion.lang.utils.collect.Lists;
import java.util.List;
/**
* 字段忽略过滤器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/10/12 11:21
*/
public class FieldIgnoreFilter implements PropertyFilter {
private final List<String> ignoreFields;
public FieldIgnoreFilter(List<String> ignoreFields) {
this.ignoreFields = ignoreFields;
}
@Override
public boolean apply(Object object, String name, Object value) {
return Lists.isEmpty(ignoreFields) || !ignoreFields.contains(name);
}
}

View File

@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 工具类
* 配置工具类
*
* @author Jiahang Li
* @version 1.0.0

View File

@@ -1,4 +1,4 @@
package com.orion.ops.framework.common.filter;
package com.orion.ops.framework.common.web.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;

View File

@@ -1,5 +1,6 @@
package com.orion.ops.framework.biz.operator.log.config;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.orion.ops.framework.biz.operator.log.core.aspect.OperatorLogAspect;
import com.orion.ops.framework.biz.operator.log.core.config.OperatorLogConfig;
@@ -7,6 +8,8 @@ import com.orion.ops.framework.biz.operator.log.core.service.OperatorLogFramewor
import com.orion.ops.framework.biz.operator.log.core.service.OperatorLogFrameworkServiceDelegate;
import com.orion.ops.framework.biz.operator.log.core.uitls.OperatorLogs;
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
import com.orion.ops.framework.common.json.filter.FieldDesensitizeFilter;
import com.orion.ops.framework.common.json.filter.FieldIgnoreFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -55,9 +58,18 @@ public class OrionOperatorLogAutoConfiguration {
@ConditionalOnBean(OperatorLogFrameworkServiceDelegate.class)
public OperatorLogAspect operatorLogAspect(OperatorLogConfig operatorLogConfig,
OperatorLogFrameworkService service) {
// 设置脱敏过滤器
OperatorLogs.setDesensitizeValueFilter(desensitizeValueFilter);
return new OperatorLogAspect(operatorLogConfig, service);
// 参数过滤器
SerializeFilter[] serializeFilters = new SerializeFilter[]{
// 忽略字段过滤器
new FieldIgnoreFilter(operatorLogConfig.getIgnore()),
// 脱敏字段过滤器
new FieldDesensitizeFilter(operatorLogConfig.getDesensitize()),
// 脱敏字段注解过滤器
desensitizeValueFilter
};
// 设置过滤器到工具类中
OperatorLogs.setSerializeFilters(serializeFilters);
return new OperatorLogAspect(operatorLogConfig, service, serializeFilters);
}
}

View File

@@ -1,7 +1,7 @@
package com.orion.ops.framework.biz.operator.log.core.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.orion.lang.define.thread.ExecutorBuilder;
import com.orion.lang.define.wrapper.Ref;
import com.orion.lang.utils.Arrays1;
@@ -64,16 +64,17 @@ public class OperatorLogAspect {
private final OperatorLogFrameworkService operatorLogFrameworkService;
@Resource
private ValueFilter desensitizeValueFilter;
private final SerializeFilter[] serializeFilters;
@Resource
private SecurityHolder securityHolder;
public OperatorLogAspect(OperatorLogConfig operatorLogConfig,
OperatorLogFrameworkService operatorLogFrameworkService) {
OperatorLogFrameworkService operatorLogFrameworkService,
SerializeFilter[] serializeFilters) {
this.operatorLogConfig = operatorLogConfig;
this.operatorLogFrameworkService = operatorLogFrameworkService;
this.serializeFilters = serializeFilters;
}
@Around("@annotation(o)")
@@ -274,7 +275,7 @@ public class OperatorLogAspect {
if (ret != null) {
if (ReturnType.JSON.equals(retType)) {
// 脱敏
model.setReturnValue(JSON.toJSONString(ret, desensitizeValueFilter));
model.setReturnValue(JSON.toJSONString(ret, serializeFilters));
} else if (ReturnType.TO_STRING.equals(retType)) {
model.setReturnValue(JSON.toJSONString(Ref.of(Objects.toString(ret))));
}

View File

@@ -1,8 +1,11 @@
package com.orion.ops.framework.biz.operator.log.core.config;
import com.orion.ops.framework.common.utils.ConfigUtils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* 操作日志配置
*
@@ -24,8 +27,27 @@ public class OperatorLogConfig {
*/
private Integer userAgentLength;
/**
* 忽略记录的字段
*/
private List<String> ignore;
/**
* 需要脱敏的字段
*/
private List<String> desensitize;
public OperatorLogConfig() {
this.errorMessageLength = 255;
this.userAgentLength = 128;
}
public void setIgnore(List<String> ignore) {
this.ignore = ConfigUtils.parseStringList(ignore);
}
public void setDesensitize(List<String> desensitize) {
this.desensitize = ConfigUtils.parseStringList(desensitize);
}
}

View File

@@ -1,7 +1,7 @@
package com.orion.ops.framework.biz.operator.log.core.uitls;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.orion.ops.framework.biz.operator.log.core.constant.OperatorLogKeys;
import com.orion.ops.framework.common.security.LoginUser;
@@ -19,7 +19,7 @@ public class OperatorLogs implements OperatorLogKeys {
private static final String UN_SAVE_FLAG = "__un__save__";
private static ValueFilter desensitizeValueFilter;
private static SerializeFilter[] serializeFilters;
/**
* 拓展信息
@@ -44,6 +44,16 @@ public class OperatorLogs implements OperatorLogKeys {
initMap().put(key, value);
}
/**
* 添加参数 json
*
* @param key key
* @param value value
*/
public static void addJson(String key, Object value) {
initMap().put(key, JSON.parseObject(JSON.toJSONString(value, serializeFilters)));
}
/**
* 添加参数
*
@@ -67,7 +77,7 @@ public class OperatorLogs implements OperatorLogKeys {
add((Map<String, ?>) obj);
return;
}
initMap().putAll(JSON.parseObject(JSON.toJSONString(obj, desensitizeValueFilter)));
initMap().putAll(JSON.parseObject(JSON.toJSONString(obj, serializeFilters)));
}
/**
@@ -147,8 +157,8 @@ public class OperatorLogs implements OperatorLogKeys {
return map;
}
public static void setDesensitizeValueFilter(ValueFilter desensitizeValueFilter) {
OperatorLogs.desensitizeValueFilter = desensitizeValueFilter;
public static void setSerializeFilters(SerializeFilter[] serializeFilters) {
OperatorLogs.serializeFilters = serializeFilters;
}
}

View File

@@ -18,6 +18,16 @@
"type": "java.lang.Integer",
"description": "userAgent 长度.",
"defaultValue": "128"
},
{
"name": "orion.operator-log.ignore",
"type": "java.util.List",
"description": "忽略记录的字段."
},
{
"name": "orion.operator-log.desensitize",
"type": "java.util.List",
"description": "需要脱敏的字段."
}
]
}

View File

@@ -7,6 +7,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
/**
@@ -29,6 +30,7 @@ public class OrionDesensitizeAutoConfiguration {
*
* @return fastjson 序列化脱敏过滤器
*/
@Primary
@Bean
public DesensitizeValueFilter desensitizeValueFilter() {
return new DesensitizeValueFilter();

View File

@@ -2,14 +2,12 @@ package com.orion.ops.framework.log.core.interceptor;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.orion.lang.utils.Arrays1;
import com.orion.lang.utils.Desensitizes;
import com.orion.lang.utils.Objects1;
import com.orion.lang.utils.collect.Maps;
import com.orion.lang.utils.reflect.Classes;
import com.orion.ops.framework.common.json.filter.FieldDesensitizeFilter;
import com.orion.ops.framework.common.json.filter.FieldIgnoreFilter;
import com.orion.ops.framework.common.meta.TraceIdHolder;
import com.orion.ops.framework.common.security.SecurityHolder;
import com.orion.ops.framework.log.core.annotation.IgnoreLog;
@@ -48,7 +46,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
/**
* 字段过滤器
*/
protected SerializeFilter[] fieldFilters;
protected SerializeFilter[] serializeFilters;
/**
* 脱敏配置
@@ -75,17 +73,15 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
public void init() {
// 请求头过滤器
this.headerFilter = header -> config.getHeaders().contains(header);
// 忽略字段过滤器
PropertyFilter ignoreFilter = (Object object, String name, Object value) -> !config.getField().getIgnore().contains(name);
// 脱敏字段过滤器
ValueFilter desensitizeFilter = (Object object, String name, Object value) -> {
if (config.getField().getDesensitize().contains(name)) {
return Desensitizes.mix(Objects1.toString(value), 1, 1);
} else {
return value;
}
// 参数过滤器
this.serializeFilters = new SerializeFilter[]{
// 忽略字段过滤器
new FieldIgnoreFilter(config.getField().getIgnore()),
// 脱敏字段过滤器
new FieldDesensitizeFilter(config.getField().getDesensitize()),
// 脱敏字段注解过滤器
desensitizeValueFilter
};
this.fieldFilters = Arrays1.of(ignoreFilter, desensitizeFilter, desensitizeValueFilter);
}
@Override
@@ -179,7 +175,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
return EMPTY_TAG;
} else if (printCount == 1) {
// 单个打印参数
return JSON.toJSONString(args[lastPrintIndex], fieldFilters);
return JSON.toJSONString(args[lastPrintIndex], serializeFilters);
} else {
// 多个打印参数
JSONArray arr = new JSONArray();
@@ -188,7 +184,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
arr.add(args[i]);
}
}
return JSON.toJSONString(arr, fieldFilters);
return JSON.toJSONString(arr, serializeFilters);
}
} catch (Exception e) {
return ERROR_TAG;
@@ -211,7 +207,7 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce
return IGNORED_TAG;
}
try {
return JSON.toJSONString(o, fieldFilters);
return JSON.toJSONString(o, serializeFilters);
} catch (Exception e) {
return ERROR_TAG;
}

View File

@@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
import com.orion.ops.framework.common.constant.FilterOrderConst;
import com.orion.ops.framework.common.filter.FilterCreator;
import com.orion.ops.framework.common.web.filter.FilterCreator;
import com.orion.ops.framework.common.security.SecurityHolder;
import com.orion.ops.framework.mybatis.core.cache.CacheClearFilter;
import com.orion.ops.framework.mybatis.core.handler.FieldFillHandler;

View File

@@ -2,12 +2,10 @@ package com.orion.ops.framework.web.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.orion.lang.utils.collect.Lists;
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
import com.orion.ops.framework.common.constant.FilterOrderConst;
import com.orion.ops.framework.common.filter.FilterCreator;
import com.orion.ops.framework.common.web.filter.FilterCreator;
import com.orion.ops.framework.web.core.filter.TraceIdFilter;
import com.orion.ops.framework.web.core.handler.GlobalExceptionHandler;
import com.orion.ops.framework.web.core.handler.WrapperResultHandler;

View File

@@ -158,13 +158,12 @@ orion:
headers:
- user-agent,accept
- content-type
# 下面引用了 需要注意
field:
ignore:
- password,newPassword
- metrics
desensitize:
- phone,phoneNumber
- email,sendEmail
storage:
# 本地文件存储
local:
@@ -198,4 +197,8 @@ orion:
keep-alive-seconds: 180
operator-log:
error-message-length: 255
user-agent-length: 128
user-agent-length: 128
ignore:
- ${orion.logging.printer.field.ignore[0]}
- ${orion.logging.printer.field.ignore[1]}
desensitize:

View File

@@ -6,7 +6,6 @@ import com.orion.lang.define.wrapper.DataGrid;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.collect.Lists;
import com.orion.office.excel.writer.exporting.ExcelExport;
import com.orion.ops.framework.biz.operator.log.core.uitls.OperatorLogs;
#if($cacheMeta.enableCache)
import com.orion.ops.framework.common.constant.Const;
#end
@@ -50,7 +49,6 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
@Override
public Long create${type}(${type}CreateRequest request) {
log.info("${type}Service-create${type} request: {}", JSON.toJSONString(request));
OperatorLogs.add(request);
// 转换
${type}DO record = ${type}Convert.MAPPER.to(request);
// 查询数据是否冲突
@@ -69,7 +67,6 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
@Override
public Integer update${type}ById(${type}UpdateRequest request) {
log.info("${type}Service-update${type}ById id: {}, request: {}", request.getId(), JSON.toJSONString(request));
OperatorLogs.add(request);
// 查询
Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING);
${type}DO record = ${typeLower}DAO.selectById(id);
@@ -180,7 +177,6 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
@Override
public Integer delete${type}ById(Long id) {
log.info("${type}Service-delete${type}ById id: {}", id);
OperatorLogs.add(OperatorLogs.ID, id);
// 检查数据是否存在
${type}DO record = ${typeLower}DAO.selectById(id);
Valid.notNull(record, ErrorMessage.DATA_ABSENT);
@@ -197,7 +193,6 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
@Override
public Integer batchDelete${type}ByIdList(List<Long> idList) {
log.info("${type}Service-batchDelete${type}ByIdList idList: {}", idList);
OperatorLogs.add(OperatorLogs.ID_LIST, idList);
int effect = ${typeLower}DAO.deleteBatchIds(idList);
log.info("${type}Service-batchDelete${type}ByIdList effect: {}", effect);
#if($cacheMeta.enableCache)
@@ -225,7 +220,6 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
@Override
public void export${type}(${type}QueryRequest request, HttpServletResponse response) throws IOException {
log.info("${type}Service.export${type} request: {}", JSON.toJSONString(request));
OperatorLogs.add(request);
// 条件
LambdaQueryWrapper<${type}DO> wrapper = this.buildQueryWrapper(request);
// 查询

View File

@@ -1,7 +1,5 @@
package com.orion.ops.module.infra.entity.request.user;
import com.orion.ops.framework.desensitize.core.annotation.Desensitize;
import com.orion.ops.framework.desensitize.core.annotation.DesensitizeObject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -15,7 +13,6 @@ import javax.validation.constraints.NotEmpty;
* @since 2023/7/13 22:16
*/
@Data
@DesensitizeObject
@Schema(name = "UserLoginRequest", description = "登陆请求")
public class UserLoginRequest {
@@ -23,7 +20,6 @@ public class UserLoginRequest {
@Schema(description = "用户名")
private String username;
@Desensitize(toEmpty = true)
@NotEmpty
@Schema(description = "密码")
private String password;