审计日志注解
1、针对增删改接口进行可视化日志审查
2、过滤敏感字段
package com.bytello.customizer.aspect;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.bytello.customizer.common.annotation.Log;
import com.bytello.customizer.common.enums.Op;
import com.bytello.customizer.common.pojo.entity.SysOpLogDo;
import com.bytello.customizer.common.pojo.entity.UserDo;
import com.bytello.customizer.common.utils.FastJsonUtil;
import com.bytello.customizer.common.utils.ServletUtil;
import com.bytello.customizer.holder.UserHolder;
import com.bytello.customizer.manager.AsyncManager;
import com.bytello.customizer.manager.factory.AsyncFactory;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
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.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 操作日志记录
*
* @author wuqinhong
* @email wuqinhong@cvte.com
* @date 2022-11-14 09:34:45
*/
@Aspect
@Component
public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/**
* 排除敏感属性字段
*/
public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword"};
// 配置织入点
@Pointcut("@annotation(com.bytello.customizer.common.annotation.Log)")
public void logPointCut() {
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
handleLog(joinPoint, controllerLog, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
handleLog(joinPoint, controllerLog, e, null);
}
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
try {
// 获取当前的用户
UserDo currentUser = UserHolder.get();
// *========数据库日志=========*//
SysOpLogDo opLog = new SysOpLogDo();
opLog.setStatus(Op.Status.SUCCESS.ordinal());
// 请求的地址
HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = req.getRemoteAddr();
opLog.setOpIp(ip);
// 操作时间
opLog.setOpTime(new Date());
// 请求地址
opLog.setOpUrl(StringUtils.substring(ServletUtil.getRequest().getRequestURI(), 0, 255));
if (currentUser != null) {
opLog.setOpName(currentUser.getAccount());
}
// 获取异常信息
if (e != null) {
opLog.setStatus(Op.Status.FAIL.ordinal());
opLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
opLog.setMethod(className + "." + methodName + "()");
// 设置请求方式
opLog.setRequestMethod(ServletUtil.getRequest().getMethod());
// 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, opLog, jsonResult);
// 保存数据库
AsyncManager.instance().execute(AsyncFactory.recordOp(opLog));
} catch (Exception exp) {
// 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param log 日志
* @param opLog 操作日志
* @throws Exception
*/
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOpLogDo opLog, Object jsonResult) throws Exception {
// 设置标题
opLog.setTitle(log.title());
//设置操作类型
opLog.setOpType(log.opType().ordinal());
// 是否需要保存request,参数和值
if (log.isSaveRequestData()) {
// 获取参数的信息,传入到数据库中。
//setRequestValue(joinPoint, opLog);
setRequestBody(opLog);
}
// 是否需要保存response,参数和值
if (log.isSaveResponseData() && jsonResult != null) {
opLog.setJsonResult(StringUtils.substring(JSONObject.toJSONString(jsonResult), 0, 2000));
}
}
/**
* 获取请求体,放到log中
*
* @param opLog
*/
private void setRequestBody(SysOpLogDo opLog){
String requestJson = ServletUtil.getRequestBody();
//过滤敏感属性
HashMap<String, String> map = FastJsonUtil.json2Map(requestJson);
String filtered = JSONObject.toJSONString(map, excludePropertyPreFilter());
opLog.setOpParam(filtered);
}
/**
* 忽略敏感属性
*/
public PropertyPreFilters.MySimplePropertyPreFilter excludePropertyPreFilter() {
return new PropertyPreFilters().addFilter().addExcludes(EXCLUDE_PROPERTIES);
}
}