思路 1。在 model层进行处理,直接重写get方法,在写一个getPlain 获取明文方法。(缺点:数据库写入和json序列化传递时使用的都是密文)
2.利用 日志组件过滤 特定的key,去进行脱敏(缺点:对所有的日志输出全部要正则匹配,非常耗时。)
由1,2的利弊,肯定会选择1,然后考虑一种实现(在model层定义方法,获取它的一个复制类,复制类里面的信息都是脱敏的,日志输出时只输出 复制对象),克服掉1的缺点
1.定义接口类
1public interface NoSensitiveObj<T> { 2 3 default T noSensitiveObj(){ 4 return (T) this; 5 } 6}
2.实现类 如果这个类没有敏感信息,只实现 NoSensitiveObj ,不需要实现里面的方法
1public class User implements NoSensitiveObj<User>{ 2 3 private String name; 4 5 private String phone; 6 7 private String email; 8 9 public String getName() { 10 return name; 11 } 12 13 public void setName(String name) { 14 this.name = name; 15 } 16 17 public String getPhone() { 18 return phone; 19 } 20 21 public void setPhone(String phone) { 22 this.phone = phone; 23 } 24 25 public String getEmail() { 26 return email; 27 } 28 29 public void setEmail(String email) { 30 this.email = email; 31 } 32 33 @Override 34 public User noSensitiveObj() { 35 User t; 36 t=new User(); 37 t.setEmail(SensitiveInfoUtils.email(email)); 38 t.setName(SensitiveInfoUtils.chineseName(name)); 39 t.setPhone(SensitiveInfoUtils.mobilePhone(phone)); 40 return t; 41 } 42 43}
3.工具类
1public class SensitiveInfoUtils { 2 3 /** 4 * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**> 5 */ 6 public static String chineseName(final String fullName) { 7 if (StringUtils.isBlank(fullName)) { 8 return ""; 9 } 10 final String name = StringUtils.left(fullName, 1); 11 return StringUtils.rightPad(name, StringUtils.length(fullName), "*"); 12 } 13 14 /** 15 * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**> 16 */ 17 public static String chineseName(final String familyName, final String givenName) { 18 if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) { 19 return ""; 20 } 21 return chineseName(familyName + givenName); 22 } 23 24 /** 25 * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762> 26 */ 27 public static String idCardNum(final String id) { 28 if (StringUtils.isBlank(id)) { 29 return ""; 30 } 31 32 return StringUtils.left(id, 3).concat(StringUtils 33 .removeStart(StringUtils.leftPad(StringUtils.right(id, 3), StringUtils.length(id), "*"), "***")); 34 } 35 36 /** 37 * [固定电话] 后四位,其他隐藏<例子:****1234> 38 */ 39 public static String fixedPhone(final String num) { 40 if (StringUtils.isBlank(num)) { 41 return ""; 42 } 43 return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"); 44 } 45 46 /** 47 * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234> 48 */ 49 public static String mobilePhone(final String num) { 50 if (StringUtils.isBlank(num)) { 51 return ""; 52 } 53 return StringUtils.left(num, 2).concat(StringUtils 54 .removeStart(StringUtils.leftPad(StringUtils.right(num, 2), StringUtils.length(num), "*"), "***")); 55 56 } 57 58 /** 59 * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****> 60 * 61 * @param sensitiveSize 62 * 敏感信息长度 63 */ 64 public static String address(final String address, final int sensitiveSize) { 65 if (StringUtils.isBlank(address)) { 66 return ""; 67 } 68 final int length = StringUtils.length(address); 69 return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*"); 70 } 71 72 /** 73 * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com> 74 */ 75 public static String email(final String email) { 76 if (StringUtils.isBlank(email)) { 77 return ""; 78 } 79 final int index = StringUtils.indexOf(email, "@"); 80 if (index <= 1) { 81 return email; 82 } else { 83 return StringUtils.rightPad(StringUtils.left(email, 1), index, "*") 84 .concat(StringUtils.mid(email, index, StringUtils.length(email))); 85 } 86 } 87 88 /** 89 * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234> 90 */ 91 public static String bankCard(final String cardNum) { 92 if (StringUtils.isBlank(cardNum)) { 93 return ""; 94 } 95 return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart( 96 StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******")); 97 } 98 99 /** 100 * [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********> 101 */ 102 public static String cnapsCode(final String code) { 103 if (StringUtils.isBlank(code)) { 104 return ""; 105 } 106 return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*"); 107 } 108 109}
4.测试
1public class Test { 2 3 private static final Logger logger=LoggerFactory.getLogger(Test.class); 4 5 public static void main(String[] args) { 6 User user=new User(); 7 user.setName("张三"); 8 user.setPhone("18666218777"); 9 user.setEmail("zhangsan@qq.com"); 10 System.out.println(JSON.toJSONString(user.noSensitiveObj())); 11 12 } 13}
结果
{"email":"z*******@qq.com","name":"张*","phone":"18******77"}
经过和同事讨论后,发现其实不需要这么复杂,只要在model 的tostring 方法中脱敏即可。