packageorg.apache.logging.log4j.spi;importjava.util.ResourceBundle;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/*** 自定义处理 日志中的敏感信息
*@authoryangw1006@163.com
**/
public classLog4jFilter {/*** 日志脱敏 开关*/
private static String LOG_FILTER_SWITH = "false";/*** 日志脱敏关键字*/
private static String LOG_FILTER_KEYS = null;static{//加载配置文件
try{//直接在本类中使用main调用时用 Properties.class.getResourceAsStream("/log4j_filter.properties");//InputStream in =Properties.class.getClassLoader().getResourceAsStream("log4j_filter.properties");//Properties p = new Properties();//p.load(in);//LOG_FILTER_SWITH = p.getProperty("log4j.filter.swith");//LOG_FILTER_KEYS = p.getProperty("log4j.filter.keys");
ResourceBundle bundle = ResourceBundle.getBundle("log4j_filter");
LOG_FILTER_SWITH= bundle.getString("log4j.filter.swith");
LOG_FILTER_KEYS= bundle.getString("log4j.filter.keys");
}catch(Exception e) {
e.printStackTrace();
}
}/*** 处理日志字符串,返回脱敏后的字符串
*@parammsg
*@return
*/
public static String invokeMsg(finalString message){
String msg= newString(message);if("true".equals(LOG_FILTER_SWITH)){//处理字符串
if(LOG_FILTER_KEYS!=null && LOG_FILTER_KEYS.length()>0){
String[] keyArr= LOG_FILTER_KEYS.split(",");for(String key: keyArr){//找key
int index= -1;do{
index= msg.indexOf(key, index+1);if(index!=-1){//判断key是否为单词字符
if(isWordChar(msg,key,index)){continue;
}//确定是单词无疑....................................//寻找值的开始位置.................................
int valueStart = getValueStartIndex(msg,index +key.length());//查找值的结束位置(逗号,分号)........................
int valueEnd =getValuEndEIndex(msg,valueStart);//对获取的值进行脱敏
String subStr =msg.substring(valueStart, valueEnd);
subStr=tuomin(subStr);///
msg = msg.substring(0,valueStart) + subStr +msg.substring(valueEnd);
}
}while(index!=-1);
}
}
}returnmsg;
}private static Pattern pattern = Pattern.compile("[0-9a-zA-Z]");/*** 判断从字符串msg获取的key值是否为单词 , index为key在msg中的索引值
*@return
*/
private static boolean isWordChar(String msg,String key, intindex){//必须确定key是一个单词............................
if(index!=0){ //判断key前面一个字符
char preCh = msg.charAt(index-1);
Matcher match= pattern.matcher(preCh+"");if(match.matches()){return true;
}
}//判断key后面一个字符
char nextCh = msg.charAt(index+key.length());
Matcher match= pattern.matcher(nextCh+"");if(match.matches()){return true;
}return false;
}/*** 获取value值的开始位置
*@parammsg 要查找的字符串
*@paramvalueStart 查找的开始位置
*@return
*/
private static int getValueStartIndex(String msg, intvalueStart ){//寻找值的开始位置.................................
do{char ch =msg.charAt(valueStart);if(ch == ':' || ch == '='){ //key 与 value的分隔符
valueStart ++;
ch=msg.charAt(valueStart);if(ch == '"'){
valueStart++;
}break; //找到值的开始位置
}else{
valueStart++;
}
}while(true);returnvalueStart;
}/*** 获取value值的结束位置
*@return
*/
private static int getValuEndEIndex(String msg,intvalueEnd){do{if(valueEnd ==msg.length()){break;
}char ch =msg.charAt(valueEnd);if(ch == '"'){ //引号时,判断下一个值是结束,分号还是逗号决定是否为值的结束
if(valueEnd+1 ==msg.length()){break;
}char nextCh = msg.charAt(valueEnd+1);if(nextCh ==';' || nextCh == ','){//去掉前面的 \ 处理这种形式的数据 "account_num\\\":\\\"6230958600001008\\\"
while(valueEnd>0){char preCh = msg.charAt(valueEnd-1);if(preCh != '\\'){break;
}
valueEnd--;
}break;
}else{
valueEnd++;
}
}else if (ch ==';' || ch == ','){break;
}else{
valueEnd++;
}
}while(true);returnvalueEnd;
}private staticString tuomin(String submsg){
StringBuffer sbResult= newStringBuffer();if(submsg!=null && submsg.length()>0){int len =submsg.length();if(len > 8){ //8位以上的 隐掉中间4位
for(int i = len-1;i>=0;i--){if(len-i<5 || len-i>8){
sbResult.insert(0, submsg.charAt(i));
}else{
sbResult.insert(0, '*');
}
}
}else{ //8位以下的全部使用 *
for(int i =0;i
sbResult.append('*');
}
}
}returnsbResult.toString();
}public static voidmain (String[] args) {//{\\\"account_num\\\":\\\"6230958600001008\\\",\\\"amount\\\":\\\"\\\"
String msg = "\\\"account_num\\\":\\\"6230958600001008\\\",\\\"amount\\\":\\\"\\\"";
System.out.println(invokeMsg(msg));
}
}