我们知道产品中需要审计日志,但是如何在保证产品开发的同时,在接口上快速添加上对应的审计日志。
前提回顾 产品角度:审计
- 用户通过统一网关访问或者操作业务A和业务B
- 业务A 和业务B 将操作日志打入到和统一日志平台约定的 TOPIC 上
- 统一日志平台消费对应的 Topic 数据,写入到对应的数据库中
- 审计员在统一日志平台上查看对应的数据
审计日志表结构
表字段 | 描述 |
---|---|
timestamp | 时间 |
ip_address | 用户IP 地址 |
user_agent | 客户端 UserAgent |
user_id | 用户ID |
operate | 操作 |
describe | 操作对象 |
根据日志表结构创建对应的对象
public class OperateLog {
private long timestamp;
private String clientIp;
private String userAgent;
private long userId;
private String operate;
private String describe;
// getSet 方法,toString 方法
}
创建 Log 注解,为了在 controller 层上添加操作日志的注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Log {
String operate() default "search";
String describe() default "";
}
创建 AOP, 这里的操作日志是在访问 controller之前就进行操作,这里是将操作日志打印在控制台上,具体代码如下所示:
import com.zion.spring.demo.annotation.Log;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.zion.spring.demo.controller.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
OperateLog operateLog = createOperateLog(joinPoint);
// 打印日志,这里可以换成写入到 Kafka
System.out.println(operateLog.toString());
}
private OperateLog createOperateLog(JoinPoint joinPoint) {
OperateLog operateLog = new OperateLog();
operateLog.setTimestamp(System.currentTimeMillis());
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
operateLog.setClientIp(request.getRemoteAddr());
operateLog.setUserAgent(request.getHeader("User-Agent"));
return appendOperate(joinPoint, operateLog);
}
private OperateLog appendOperate(JoinPoint joinPoint, OperateLog operateLog) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
Log annotation = method.getAnnotation(Log.class);
if (annotation != null) {
operateLog.setOperate(annotation.operate());
operateLog.setDescribe(annotation.describe());
}
return operateLog;
}
}
Controller 上唯一的变化就是针对每一个请求,添加对应的操作日志描述(Log 注解),如下所示:
import com.zion.spring.demo.HelloService;
import com.zion.spring.demo.MyBean;
import com.zion.spring.demo.annotation.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
private HelloService service;
@GetMapping("/message")
@Log(describe = "获取信息")
public String getMessage() {
return service.getMessage();
}
}
总结
以上就是通过横向切面的方式,添加对应的操作日志,业务人员只需要专注在业务上的实现,而不需要关心操作日志的内容。