logback日志脱敏后异步写入文件

        大家项目中肯定都会用到日志打印,目的是为了以后线上排查问题方便,但是有些企业对输出的日志包含的敏感(比如:用户身份证号,银行卡号,手机号等)信息要进行脱敏处理。

       哎!我们最近就遇到了日志脱敏的改造。可以说是一波三折。

        浩浩荡荡的日志脱敏改造就这样开始..........

              第一季 :在项目中所有log.info方法输出日志的地方手工脱敏,很low的一种方法

        初期想法很简单,就是根据业务,判断哪些info输出的地方可能包含敏感信息,然后进行手工脱敏。但是有很大弊端,一是工作量大,二是业务不熟悉很难一次改全。

脱敏工具类:

package com.lsl.utills;public class Utils {public static String checkParams(String str){if (str != null){String strnew = str.replaceAll("1[3-9]\\d{9}","***");return strnew;}else {return "";}}
}

代码中调用这个工具类:

package com.lsl.controller;import com.lsl.utills.Utils;
import com.lsl.vo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
@RequestMapping("/lsl")
public class LogbackTestController {private static final Logger LOG = LoggerFactory.getLogger(LogbackTestController.class);@PostMapping(value = "qryUser", produces = "application/json;charset=UTF-8")@ResponseBodypublic String qryUser(){User user = new User();user.setUserName("LSL");user.setUserPwd("123@asd");user.setUserAddr("北京海淀");user.setUserAge(21);user.setUserTel("15803125588");LOG.info("用户信息:{}",user.toString());LOG.info("脱敏后的用户信息:{}", Utils.checkParams(user.toString()));return "success";}
}

结果截图:

        这种情况确实也能达到脱敏的目的,但是如果代码中有好多info日志输出,那么都需要改动,工作量太大,还容易拉下没有改动的地方。其实我们初期就是这种脱敏,反复改了好几次,总有遗漏的地方忘记改了。

        第二季:想研究一种省时省力的方式,能不能通过AOP切入log.info方法进行统一脱敏

大概思路,就是创建一个切面,在调用info方法前把打印内容通过上面的工具类脱敏后在打印。

切面:

package com.lsl.config;import com.lsl.utills.Utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class LogInfoAspect {@Pointcut("execution(* org.slf4j.Logger.info(..))")public void loginfoPointcut(){}@Before("loginfoPointcut() && args(msg)")public void bfLogInfo(ProceedingJoinPoint joinPoint,String msg) throws Throwable{System.out.println("切入前参数msg=" + msg);String newStr = Utils.checkParams(msg);System.out.println("脱敏处理后参数=" + newStr);joinPoint.proceed(new Object[]{newStr});}@Around("loginfoPointcut() && args(msg)")public void adLogInfo(ProceedingJoinPoint joinPoint,String msg) throws Throwable{
//        String arg = (String)joinPoint.getArgs()[0];System.out.println("切入前参数msg=" + msg);String newStr = Utils.checkParams(msg);System.out.println("脱敏处理后参数=" + newStr);joinPoint.proceed(new Object[]{newStr});}
}

结果是:没法切入到info方法,也就无法脱敏了

如下图:

原因也很简单:AOP是交付spring托管的bean才能使用动态代理,实现切入进行操作。然后logback并没有由spring托管,所以不行。

我后来想到,在配置类里交付spring托管不就行了,但是也不行,大家猜猜是什么原因呢?

                        第三季:利用logback脱敏并实现异步写入日志文件

大概思路是,需要自己写脱敏转换器,然后引入logback.xml中,异步写入文件比较方便,网上好多资料,大家可以自行查询。

脱敏转换器:

package com.lsl.config;import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.lang3.StringUtils;import java.util.regex.Matcher;
import java.util.regex.Pattern;public class SensitiveConverter extends MessageConverter {//手机号正则private static final String PHONE_REG = "(1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}|[96]\\d{7}|6[68]\\d{5}|09\\d{8})([^@^\\d]|$)";//身份证号正则private static final String IDCARD_REG = "";//脱敏字符private static final String SECRET = "***************";//要脱敏的类型private static String sensitiveType;public static void setSensitiveType(String sensitiveType){SensitiveConverter.sensitiveType = sensitiveType;}@Overridepublic String convert(ILoggingEvent event){String requestLogMsg = event.getFormattedMessage();return filtrSensitive(requestLogMsg,sensitiveType);}public String filtrSensitive(String content,String sensitiveType){try {if (StringUtils.isBlank(content)){return content;}//手机号脱敏if (sensitiveType.contains("phone")){content = filterPhone(content);}//身份证脱敏if (sensitiveType.contains("idcard")){}return content;} catch (Exception e) {return content;}}private static String filterPhone(String num){Pattern pattern =  Pattern.compile(PHONE_REG);Matcher matcher = pattern.matcher(num);StringBuffer sb = new StringBuffer();while (matcher.find()){String matchResult = matcher.group();if (!StringUtils.isNumeric(matchResult.substring(matchResult.length() - 1))){//大陆手机号if (matchResult.startsWith("1")){matcher.appendReplacement(sb,baseSensitive(matchResult,3,5));}//港澳手机号if (matchResult.startsWith("6") || matchResult.startsWith("9")){}}else {//大陆手机号if (matchResult.startsWith("1")){matcher.appendReplacement(sb,baseSensitive(matchResult,3,4));}//港澳手机号if (matchResult.startsWith("6") || matchResult.startsWith("9")){}}}matcher.appendTail(sb);return sb.toString();}private static String baseSensitive(String str,int startlen,int endlen){if (StringUtils.isBlank(str)){return "";}StringBuffer sb = new StringBuffer();sb.append(SECRET);return StringUtils.left(str,startlen).concat(StringUtils.leftPad(StringUtils.right(str,endlen),str.length()- startlen,sb.toString()));}}
package com.lsl.config;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class SensitiveConverterProperties implements InitializingBean {@Value("${logging.sensitive.type}")private String sensitiveType;@Overridepublic void afterPropertiesSet() throws Exception {SensitiveConverter.setSensitiveType(this.sensitiveType);}public String getSensitiveType() {return sensitiveType;}public void setSensitiveType(String sensitiveType) {this.sensitiveType = sensitiveType;}
}

application.properties文件


server.port=8080logging.sensitive.type=phone

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!--    转换配置 必选配置--><conversionRule conversionWord="sensitiveMsg" converterClass="com.lsl.config.SensitiveConverter"> </conversionRule><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %sensitiveMsg%n</pattern></encoder></appender><!-- 按照每天生成日志文件 --><appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/app.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>30</maxHistory></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %sensitiveMsg%n</pattern></encoder></appender><!-- 异步日志配置 --><appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="ROLLING" /></appender><!-- 项目包下所有info日志输出到控制台 --><logger name="com.lsl" level="INFO" additivity="false"><appender-ref ref="CONSOLE" /></logger><!-- 项目包下所有info日志异步输出到文件 --><logger name="com.lsl" level="INFO" additivity="false"><appender-ref ref="ASYNC_FILE" /></logger><!-- Root Logger --><root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="ROLLING" /></root>
</configuration>

controoler验证

package com.lsl.controller;import com.lsl.vo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
@RequestMapping("/lsl")
public class LogbackTestController {private static final Logger LOG = LoggerFactory.getLogger(LogbackTestController.class);@PostMapping(value = "qryUser", produces = "application/json;charset=UTF-8")@ResponseBodypublic String qryUser(){User user = new User();user.setUserName("LSL");user.setUserPwd("123@asd");user.setUserAddr("北京海淀");user.setUserAge(21);user.setUserTel("15803125588");LOG.info("用户信息:{}",user.toString());return "success";}
}

验证截图

总结:

利用logback的脱敏转换器是非常方便且灵活的。自己可以定义各种业务敏感信息的脱敏策略,我这里面只写了手机号的脱敏策略。而且在配置文件properties中可以配置对那些敏感信息进行脱敏。

比如:logging.sensitive.type=phone,idcard  

这样就是手机号和身份证号同时进行脱敏,只是具体的身份证号的脱敏规则,我以后在补上吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/457154.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用text-embedding-3-small生成向量并将向量插入Mlivus Cloud用于语义搜索的深度解析与实战操作

使用text-embedding-3-small生成向量并将向量插入Mlivus Cloud用于语义搜索的深度解析与实战操作 在当今的大数据时代,文本数据的处理与分析显得尤为重要。如何高效地存储、查询和理解这些海量文本数据,成为了许多企业和研究机构面临的重大挑战。幸运的是,随着向量数据库技…

校园表白墙源码修复版

此校园表白墙源码基于thinkphp&#xff0c;因为时代久远有不少bug&#xff0c;经本人修复已去除大部分bug&#xff0c;添加了美化元素。 https://pan.quark.cn/s/1f9b3564c84b https://pan.baidu.com/s/1bb9vu9VV2jJoo9-GF6W3xw?pwd7293 https://caiyun.139.com/m/i?2hoTc…

用更多的钱买电脑而不是手机

如果&#xff0c;我们对自己的定义是知识工作者&#xff0c;那么在工作、学习相关的电子设备投入上&#xff0c;真的别舍不得花钱。 需要留意的是&#xff0c;手机&#xff0c;对于大部分在电脑前工作的人&#xff0c;不是工作设备。在我看来&#xff0c;每年投入到电脑的钱&…

【Java】java 集合框架(详解)

&#x1f4c3;个人主页&#xff1a;island1314 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f49e; &#x1f49e; &#x1f49e; 1. 概述 &#x1f680; &#x1f525; Java集合框架 提供了一系列用于存储和操作…

GeoWebCache1.26调用ArcGIS切片

常用网址&#xff1a; GeoServer GeoWebCache (osgeo.org) GeoServer 用户手册 — GeoServer 2.20.x 用户手册 一、版本需要适配&#xff1a;Geoserver与GeoWebCache、jdk等的版本适配对照 ​ 查看来源 二、准备工作 1、数据&#xff1a;Arcgis标准的切片&#xff0c;通过…

前OpenAI首席技术官为新AI初创公司筹资;我国发布首个应用临床眼科大模型 “伏羲慧眼”|AI日报

文章推荐 2024人工智能报告.zip &#xff5c;一文迅速了解今年的AI界都发生了什么&#xff1f; 今日热点 据报道&#xff0c;前OpenAI首席技术官Mira Murati正在为一家新的AI初创公司筹集资金 据路透社报道&#xff0c;上个月宣布离职的OpenAI首席技术官Mira Murati正在为一…

2024年妈杯MathorCup大数据竞赛A题超详细解题思路

2024年妈杯大数据竞赛初赛整体难度约为0.6个国赛。A题为台风中心路径相关问题&#xff0c;为评价预测问题&#xff1b;B题为库存和销量的预测优化问题。B题难度稍大于A题&#xff0c;可以根据自己队伍情况进行选择。26日早六点之前发布AB两题相关解题代码论文。 下面为大家带来…

excel斜线表头

检验数据验证对象 鼠标放在检验数据 验证对象中间&#xff0c;altenter 之后空格 选中格子&#xff0c;右键单元格格式&#xff0c; 完成 如果是需要多分割&#xff0c;操作一样&#xff0c;在画斜线的时候会有区别&#xff0c;在插入里面用直线画斜线即可 在表格插入的时…

el-table相关的功能实现

1. 表格嵌套表格时&#xff0c;隐藏父表格的全选框 场景&#xff1a;当table表格设置复选&#xff08;多选&#xff09;功能时&#xff0c;如何隐藏表头的复选框&#xff0c;不让用户一键多选。 <el-table :header-cell-class-name"cellClass">// 表头复选框禁…

基于Springboot无人驾驶车辆路径规划系统(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

雷赛L6N伺服驱动器基本参数设置——EtherCAT 总线型

1、指令脉冲设置 PA0.08代表电机转一圈&#xff0c;所需要的指令脉冲数&#xff0c;该值驱动器默认值为0&#xff0c;该值更改后断电重启后生效。 2、编码器反馈脉冲设置 PA0.11&#xff0c;代表编码器输出每转脉冲数&#xff0c;实际反馈的脉冲数做了4倍频处理&#xff0c;设…

CSS揭秘:7. 伪随机背景

前置知识&#xff1a;CSS 渐变&#xff0c;5. 条纹背景&#xff0c;6. 复杂的背景图案 前言 本篇主要内容依然是关于背景的&#xff0c;无限平铺的背景会显得整齐美观&#xff0c;但又有些呆板&#xff0c;如何实现背景的多样性和随机性&#xff0c;是本篇的核心。 一、四种颜…

LTSC版本的Windows系统没有默认图片查看工具和便笺?教你下载。

前言 最近小白在使用Windows 11 LTSC版本&#xff0c;感觉真的是嘎嘎好用。 终于等到了&#xff01;旧电脑福星——最干净的Win11官方原版系统 小白用来安装这个系统的电脑配置其实也不低&#xff1a; i5-12400&#xff08;核显输出&#xff09; 16GB DDR4 3200MHz 500GB …

植物健康,Spring Boot来助力

3系统分析 3.1可行性分析 通过对本植物健康系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本植物健康系统采用SSM框架&#xff0c;JAVA作为开发语言&#…

【c++篇】:从基础到实践--c++内存管理技巧与模版编程基础

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.c/c内存分布二.c/c的动态内存管理方式2.1.c语言的动态内存管…

Rust初踩坑

一、下载 到官网https://www.rust-lang.org/zh-CN/tools/install下载你需要的版本 二、安装 执行rustup-init 文件&#xff0c;选择1 按提示直到安装完成 可以通过以下命令测试&#xff1a; rustc -V # 注意的大写的 V cargo -V # 注意的大写的 V三、在VScode中…

Linux--epoll(ET)实现Reactor模式

Linux–多路转接之epoll Reactor反应堆模式 Reactor反应堆模式是一种事件驱动的设计模式&#xff0c;通常用于处理高并发的I/O操作&#xff0c;尤其是在服务器或网络编程中。 基本概念 Reactor模式又称之为响应器模式&#xff0c;基于事件多路复用机制&#xff0c;使得单个…

UDP(用户数据报协议)端口监控

随着网络的扩展&#xff0c;确保高效的设备通信对于优化网络功能变得越来越重要。在这个过程中&#xff0c;端口发挥着重要作用&#xff0c;它是实现外部设备集成的物理连接器。通过实现数据的无缝传输和交互&#xff0c;端口为网络基础设施的顺畅运行提供了保障。端口使数据通…

vuex使用modules模块化

1、main.js引入 //引入vuex import store from ./store new Vue({el: #app,router,store,components: { App },template: <App/>,data:function(){return{wbWinList: [] // 定义的变量&#xff0c;全局参数}}, })2、index.js import Vue from vue; import Vuex from …

python实战(一)——iris鸢尾花数据集分类

一、任务背景 本文是python实战系列专栏的第一篇文章&#xff0c;我们将从分类开始由浅入深逐步学习如何使用python完成常规的机器学习/深度学习任务。iris数据集是经典的机器学习入门数据集&#xff0c;许多分类任务教程都会以这个数据集作为示例&#xff0c;它的数据量是150条…