1. 引入依赖
//脱敏工具包
implementation 'com.github.houbb:sensitive-core:0.0.9'
implementation 'com.alibaba:fastjson:1.2.75'
2. 配置文件
- application.properties中配置需要脱敏的字段名称
exclude.properties=name,phoneNo,password
3. 注解类
package com.example.fisher.gradledemo.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
}
4. 切面类
- 提供2种方式脱敏
- fastjson脱敏字段不显示,sensitive-core将带有脱敏注解的属性字段部分显示***
package com.example.fisher.gradledemo.aspectj;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.example.fisher.gradledemo.dto.LogInfo;
import com.github.houbb.sensitive.core.api.SensitiveUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Slf4j
@Component
@Aspect
public class LogAspect {
/**
* 配置需要脱敏的字段名
*/
@Value("${exclude.properties}")
private Set<String> properties;
public static final String DESENSITISE_MSG = "******";
/**
* 忽略敏感属性
*/
public PropertyPreFilters.MySimplePropertyPreFilter excludePropertyPreFilter() {
return new PropertyPreFilters().addFilter().addExcludes(properties.toArray(String[]::new));
}
/**
* 包路径
*/
@Pointcut("execution(public * com.example.fisher.gradledemo.sysuser.controller.*.*(..))")
public void pc1() {}
/**
* 注解
*/
@Pointcut("@annotation(com.example.fisher.gradledemo.annotation.Log)")
public void pc2() {}
@Around("pc1()||pc2()")
public Object around(ProceedingJoinPoint point) throws Throwable {
// 入参使用fastjson进行脱敏,脱敏字段不显示
LogInfo loginfo = getLoginfo(point);
Object result = point.proceed();
// 返回值使用sensitive-core工具包进行脱敏,脱敏字段部分显示***
Object deSensitiveObject = getDeSensitiveObject2(null, result);
loginfo.setResult(String.valueOf(deSensitiveObject));
log.info("{}", loginfo);
return result;
}
/**
* 记录异常日志
*/
@AfterThrowing(value = "pc1()||pc2()", throwing = "e")
public void afterThrowing(JoinPoint point, Throwable e) {
LogInfo loginfo = getLoginfo(point);
log.error("{},{}", loginfo, e);
}
/**
* 需要打印的日志信息
*
* @param point
* @return
*/
private LogInfo getLoginfo(JoinPoint point) {
String className = point.getTarget().getClass().getName();
MethodSignature signature = (MethodSignature)point.getSignature();
String methodName = signature.getName();
HttpServletRequest request = getRequestAttributes().getRequest();
LogInfo logInfo = new LogInfo();
logInfo.setClassName(className);
logInfo.setMethodName(methodName);
logInfo.setUrl(request.getRequestURI());
logInfo.setHttpMethod(request.getMethod());
logInfo.setIpAddress(request.getRemoteAddr());
// 获取入参
Object[] args = point.getArgs();
String[] parameterNames = signature.getParameterNames();
Map<String, Object> inputParam = getInputParam(parameterNames, args);
logInfo.setParameter(String.valueOf(inputParam));
return logInfo;
}
/**
* 获取入参
*
* @param parameterNames
* @param args
* @return
*/
private Map<String, Object> getInputParam(String[] parameterNames, Object[] args) {
Map<String, Object> map = new HashMap<>(16);
for (int i = 0; i < parameterNames.length; i++) {
String parameterName = parameterNames[i];
Object arg = args[i];
Object deSensitiveObject = getDeSensitiveObject(parameterName, arg);
map.put(parameterName, deSensitiveObject);
}
return map;
}
/**
* 参数脱敏,如果是对象使用fastjson根据脱敏字段进行脱敏,字段不显示
*
* @param parameterName
* @param arg
* @return
*/
private Object getDeSensitiveObject(String parameterName, Object arg) {
Class<?> clazz = arg.getClass();
if (arg instanceof MultipartFile || arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
return "";
} else if (String.class.isAssignableFrom(clazz)) {
if (properties.contains(parameterName)) {
return DESENSITISE_MSG;
}
} else if (Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz)) {
arg = JSONObject.toJSONString(arg, excludePropertyPreFilter());
} else {
arg = JSONObject.toJSONString(arg, excludePropertyPreFilter());
}
return arg;
}
/**
* 参数脱敏,对象使用sensitive-core工具包进行脱敏,不同注解使用不同方式脱敏,比如密码不显示,手机号、姓名部分显示***
*
* @param parameterName
* @param arg
* @return
*/
private Object getDeSensitiveObject2(String parameterName, Object arg) {
Class<?> clazz = arg.getClass();
if (arg instanceof MultipartFile || arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
return "";
} else if (String.class.isAssignableFrom(clazz)) {
if (properties.contains(parameterName)) {
return DESENSITISE_MSG;
}
} else if (Collection.class.isAssignableFrom(clazz) ) {
arg = SensitiveUtil.desCopyCollection((Collection<?>)arg);
}else if (Map.class.isAssignableFrom(clazz)){
HashMap<Object, Object> hashMap = new HashMap<>(16);
((Map)arg).forEach((s, o) -> {
if (properties.contains(String.valueOf(s))) {
hashMap.put(s, DESENSITISE_MSG);
} else {
hashMap.put(s, o);
}
});
arg = hashMap;
}else {
//当做对象处理
arg = SensitiveUtil.desJson(arg);
}
return arg;
}
/**
* 获取request对象
*
* @return
*/
public ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes)attributes;
}
}
5. 需要脱敏的实体类
- 在需要脱敏的属性上添加注解,例如@SensitiveStrategyChineseName,@SensitiveStrategyPhone等
- 这里使用了mybatis-plus
package com.example.fisher.gradledemo.sysuser.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.github.houbb.sensitive.annotation.strategy.SensitiveStrategyChineseName;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@SuppressWarnings("serial")
@Data
public class SysUser extends Model<SysUser> {
@TableId(type = IdType.AUTO)
private Long userId;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
@TableLogic
@JsonIgnore
private Integer delFlag;
@SensitiveStrategyChineseName
private String name;
private Integer age;
private String interest;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
public Serializable pkVal() {
return this.userId;
}
}
6. 查看日志打印
版权声明:本文为qq_40977118原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。