切面日志脱敏

x33g5p2x  于9个月前 转载在 其他  
字(2.7k)|赞(0)|评价(0)|浏览(605)

原有切面形式对controller进来的请求记录日志,但对于一些敏感信息,比如密码、手机号打印在日志中存在泄露风险

由于应用中已经使用了AOP的方式记录请求日志,所以直接从切面判断并且将内容转密文打印。为了更加方便、灵活的设置需要遮掩的字段内容,采用注解的方式将需要遮掩的字段标记,在切面中进行识别处理

需要处理字段标记注解

  1. @Target({ElementType.FIELD, ElementType.PARAMETER})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface EncryptLog {
  4. }

应用拦截请求日志代码

  1. @Aspect
  2. @Component
  3. @Slf4j
  4. public class WebLogAspect {
  5. /**
  6. * 指定 controller 包下的注解
  7. */
  8. @Pointcut("execution( * com.test.cloud.api.web.controller.*.*(..))")
  9. public void logPointCut() {
  10. }
  11. /**
  12. * 指定当前执行方法在logPointCut之前执行
  13. */
  14. @Before("logPointCut()")
  15. public void doBefore(JoinPoint joinPoint) {
  16. MDC.put("TRACE_ID", StrUtil.removeAll(UUID.randomUUID().toString(), "-"));
  17. // 接收到请求,记录请求内容
  18. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  19. HttpServletRequest request = attributes.getRequest();
  20. List<Object> printArgs = getPrintArgs(joinPoint.getArgs());
  21. // 记录下请求内容
  22. log.info("请求ip:{},请求地址:{},请求类型:{}", HttpUtils.getIpAddr(request), request.getRequestURL().toString(), request.getMethod());
  23. log.info("请求方法:{}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
  24. log.info("参数:{}", printArgs.toArray());
  25. }
  26. @NotNull
  27. private List<Object> getPrintArgs(Object[] args) {
  28. List<Object> printArgs = new ArrayList<>(args.length);
  29. for (Object arg : args) {
  30. if (arg instanceof ServletRequest || arg instanceof ServletResponse) {
  31. continue;
  32. }
  33. //复制一份,避免修改原内容
  34. Object copyArg = BeanUtil.copyProperties(arg, arg.getClass());
  35. for (Field field : copyArg.getClass().getDeclaredFields()) {
  36. EncryptLog tag = field.getAnnotation(EncryptLog.class);
  37. if (tag != null) {
  38. field.setAccessible(true);
  39. try {
  40. field.set(copyArg, "******");
  41. } catch (IllegalAccessException e) {
  42. log.error(e.getMessage(), e);
  43. }
  44. }
  45. }
  46. printArgs.add(copyArg);
  47. }
  48. return printArgs;
  49. }
  50. /**
  51. * 指定在方法之后返回
  52. */
  53. @AfterReturning(returning = "ret", pointcut = "logPointCut()")
  54. public void doAfterReturning(Object ret) {
  55. // 处理完请求,返回内容
  56. log.info("返回值 :{}", getPrintArgs(new Object[]{ret}));
  57. MDC.clear();
  58. }
  59. @Around("logPointCut()")
  60. public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
  61. StopWatch sw = new StopWatch();
  62. sw.start();
  63. Object ob = pjp.proceed();
  64. sw.stop();
  65. log.info("耗时 :{} ms", sw.getTotalTimeMillis());
  66. return ob;
  67. }

demo

  1. @Data
  2. public class AccountLoginRequest {
  3. @NotBlank(message = "请填写账号")
  4. private String account;
  5. @EncryptLog
  6. @NotBlank(message = "请填写密码")
  7. private String password;
  8. }

效果

  1. 请求ip:127.0.0.1,请求地址:http://127.0.0.1:8999/login/account,请求类型:POST
  2. 请求方法:com.test.cloud.api.web.controller.UserLoginController.accountLogin
  3. 参数:AccountLoginRequest(account=test@163.com, password=******)

本文来自博客园,作者:IAyue,转载请注明原文链接:https://www.cnblogs.com/zmj-pr/p/17664331.html

相关文章