无论对于什么业务来说,用户数据信息的安全性无疑都是非常重要的。尤其是在数字经济大火背景下,数据的安全性就显得更加重要。数据脱敏可以分为两个部分,一个是DB层面,防止DB数据泄露,暴露用户信息;一个是接口层面,有些UI展示需要数据脱敏,防止用户信息被人刷走了。
DB层面的脱敏今天先不讲,今天先讲讲依赖于注解的接口层面的数据脱敏,接口层面的脱敏可能最原始和简单的方法就是在每个controller输出数据时,硬性处理。但是这么做的方案,如果后续脱敏规则改了,那需要改的地方就太多了,而且很容易有遗漏的地方,造成全站脱敏规则不统一的情况。所以我们建议的是用注解的方式,可插拔性更好,随时可以更改规则,更加的灵活。
我们今天接到的需求是这样的:
页面或者接口层面的脱敏,大多也是围绕用户手机号啊、真实姓名或者地址等等展开的。
这里定义一个敏感字段的枚举,并设定各个字段的脱敏策略。
/** * @Author tou tou * @Date 2023/1/15 * @Des 脱敏类型及策略,不同的字段类型适配不同的策略 */ public enum SensitivityEnum { /** * 用户名 */ USERNAME(s -> s.replaceAll("\\S*(\\S)", "***$1")), /** * 身份证 */ ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")), /** * 手机号 */ PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")), /** * 地址 */ ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****")); private final Function<String, String> desensitizer; SensitivityEnum(Function<String, String> desensitizer) { this.desensitizer = desensitizer; } public Function<String, String> desensitizer() { return desensitizer; } }
都说了,我们使用的是注解的方式脱敏,所以是需要声明一个脱敏注解的,需要用到的地方,按需声明注解即可。非常方便。
/** * @Author tou tou * @Date 2023/1/15 * @Des */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @JacksonAnnotationsInside @JsonSerialize(using = SensitivitySerializer.class) public @interface Sensitivity { SensitivityEnum strategy(); }
/** * @Author tou tou * @Date 2023/1/15 * @Des */ public class SensitivitySerializer extends JsonSerializer<String> implements ContextualSerializer { private SensitivityEnum sensitivityEnum; @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(sensitivityEnum.desensitizer().apply(value)); } @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { Sensitivity annotation = property.getAnnotation(Sensitivity.class); if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) { this.sensitivityEnum = annotation.strategy(); return this; } return prov.findValueSerializer(property.getType(), property); } }
@Sensitivity
注解的实体类public class UserAccountVO { private Integer id; @Sensitivity(strategy = SensitivityEnum.USERNAME) private String username; private Integer age; @Sensitivity(strategy = SensitivityEnum.PHONE) private String tel; private String email; private String account; }
create table useraccount ( id INT(11), username NVARCHAR(25), age INT(11), phone bigint, email VARCHAR(80), account VARCHAR(20), pwd VARCHAR(20) ); select * from useraccount; insert into useraccount values(1,'张老三', 22, 13555551111,'13555551111@126.com','z13555551111', '13555551111');
/** * @author toutou * @date by 2019/07 */ @RestController public class UserController { @Autowired UserAccountService userAccountService; @GetMapping("/user/getuser") public Result getUserAccountById(@RequestParam("uid") int id){ UserAccountVO user = userAccountService.getUserAccountById(id); if(user != null){ return Result.setSuccessResult(user); }else{ return Result.setErrorResult(404, "用户不存在"); } } }
https://github.com/toutouge/javademosecond/tree/master/hellolearn
作 者:请叫我头头哥
出 处:http://www.cnblogs.com/toutou/
关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
博主尝试通过gitee的发行版,使用Springboot为基础框架,逐步整合JWT、JPA、VUE等常用功能项目。【本节完成】使用bcprov-jdk18on的sm2加密算法对用户密码进行签名及认证