切面日志脱敏

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

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

需要处理字段标记注解

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

}

应用拦截请求日志代码

@Aspect
@Component
@Slf4j
public class WebLogAspect {

    /**
     * 指定 controller 包下的注解
     */
    @Pointcut("execution( * com.test.cloud.api.web.controller.*.*(..))")
    public void logPointCut() {

    }

    /**
     * 指定当前执行方法在logPointCut之前执行
     */
    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        MDC.put("TRACE_ID", StrUtil.removeAll(UUID.randomUUID().toString(), "-"));
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        List<Object> printArgs = getPrintArgs(joinPoint.getArgs());

        // 记录下请求内容
        log.info("请求ip:{},请求地址:{},请求类型:{}", HttpUtils.getIpAddr(request), request.getRequestURL().toString(), request.getMethod());
        log.info("请求方法:{}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("参数:{}", printArgs.toArray());
    }

    @NotNull
    private List<Object> getPrintArgs(Object[] args) {
        List<Object> printArgs = new ArrayList<>(args.length);

        for (Object arg : args) {

            if (arg instanceof ServletRequest || arg instanceof ServletResponse) {
                continue;
            }
               
            //复制一份,避免修改原内容
            Object copyArg = BeanUtil.copyProperties(arg, arg.getClass());
            for (Field field : copyArg.getClass().getDeclaredFields()) {
                EncryptLog tag = field.getAnnotation(EncryptLog.class);
                if (tag != null) {
                    field.setAccessible(true);
                    try {
                        field.set(copyArg, "******");
                    } catch (IllegalAccessException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }
            printArgs.add(copyArg);
        }
        return printArgs;
    }

    /**
     * 指定在方法之后返回
     */
    @AfterReturning(returning = "ret", pointcut = "logPointCut()")
    public void doAfterReturning(Object ret) {
        // 处理完请求,返回内容
        log.info("返回值 :{}", getPrintArgs(new Object[]{ret}));

        MDC.clear();
    }

    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        StopWatch sw = new StopWatch();
        sw.start();
        Object ob = pjp.proceed();
        sw.stop();
        log.info("耗时 :{} ms", sw.getTotalTimeMillis());
        return ob;
    }

demo

@Data
public class AccountLoginRequest {

    @NotBlank(message = "请填写账号")
    private String account;

    @EncryptLog
    @NotBlank(message = "请填写密码")
    private String password;

}

效果

请求ip:127.0.0.1,请求地址:http://127.0.0.1:8999/login/account,请求类型:POST
请求方法:com.test.cloud.api.web.controller.UserLoginController.accountLogin
参数:AccountLoginRequest(account=test@163.com, password=******)
posted @ 2023-08-30 17:59  IAyue  阅读(38)  评论(0编辑  收藏  举报