场景:响应政府要求,商业软件应保证用户基本信息不被泄露,不能直接展示用户手机号,身份证,地址等敏感信息。
根据上面场景描述,我们可以分析出两个点。
- 不被泄露说明用户信息应被加密储存;
- 不能直接展示说明用户信息应脱敏展示;
解决方案
- 傻瓜式编程:将项目中关于用户信息实体类的字段,比如姓名,手机号,身份证,地址等,在新增进数据库之前,对数据进行加密处理;在列表中展示用户信息时,对数据库中的数据进行解密脱敏,然后返回给前端;
- 切入式编程:将项目中关于用户信息实体类的字段用注解给标记,新增用户信息实体类(这里我们用UserBO来表示,给UserBO里面的name,phone字段添加@EncryptField),返回用户信息实体类(这里我们用UserDO来表示,给UserDO里面的name,phone字段添加@DecryptField);然后利用@EncryptField,@DecryptField做为切入点,以切面的形式实现加密,解密脱敏;
傻瓜式编程不是说傻,而是相当于切入式编程,傻瓜式编程需要对用户信息相关的所有接口进行加密,解密脱敏的逻辑处理,这里改动的地方就比较多,风险高,重复操作相同的逻辑,工作量大,后期不好维护;切入式编程只需要对用户信息字段添加注解,对有注解的字段统一进行加密,解密脱敏逻辑处理,操作方便,高聚合,易维护;
方案实现
傻瓜式编程没什么难度,这里我给大家有切入式编程来实现;在实现之前,跟大家预热一下注解,反射,AOP的知识;
注解实战
创建注解
创建一个只能标记在方法上的注解:
java复制代码package com.weige.javaskillpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) //METHOD 说明该注解只能用在方法上
@Retention(RetentionPolicy.RUNTIME) //RUNTIME 说明该注解在运行时生效
public @interface Encryption {
}
创建一个只能标记在字段上的注解:
java复制代码package com.weige.javaskillpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) //FIELD 说明该注解只能用在字段上
@Retention(RetentionPolicy.RUNTIME) //RUNTIME 说明该注解在运行时生效
public @interface EncryptField {
}
创建一个标记在字段上,且有值的注解:
java复制代码package com.weige.javaskillpoint.annotation;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptField {
// 注解是可以有值的,这里可以为数组,String,枚举等类型
// DesensitizationEnum desensitizationEnum = field.getAnnotation(DecryptField.class).value(); 这里的field是指当前标记的字段
DesensitizationEnum value();
}
注解使用
创建枚举
java复制代码package com.weige.javaskillpoint.enums;
public enum DesensitizationEnum {
name, // 用户信息姓名脱敏
address, // 用户信息地址脱敏
phone; // 用户信息手机号脱敏
}
创建UserDO类
java复制代码package com.weige.javaskillpoint.entity;
import com.weige.javaskillpoint.annotation.DecryptField;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
import com.weige.javaskillpoint.utils.AesUtil;
import java.lang.reflect.Field;
// 用户信息返回实体类
public class UserDO {
@DecryptField(DesensitizationEnum.name)
private String name;
@DecryptField(DesensitizationEnum.address)
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public UserDO(String name, String address) {
this.name = name;
this.address = address;
}
public static void main(String[] args) throws IllegalAccessException {
// 生成并初始化对象
UserDO userDO = new UserDO("梦想是什么","湖北省武汉市");
// 反射获取当前对象的所有字段
Field[] fields = userDO.getClass().getDeclaredFields();
// 遍历字段
for (Field field : fields) {
// 判断字段上是否存在@DecryptField注解
boolean hasSecureField = field.isAnnotationPresent(DecryptField.class);
// 存在
if (hasSecureField) {
// 暴力破解 不然操作不了权限为private的字段
field.setAccessible(true);
// 如果当前字段在userDo中不为空 即name,address字段有值
if (field.get(userDO) != null) {
// 获取字段上注解的value值
DesensitizationEnum desensitizationEnum = field.getAnnotation(DecryptField.class).value();
// 控制台输出
System.out.println(desensitizationEnum);
// 根据不同的value值 我们可以对字段进行不同逻辑的脱敏 比如姓名脱敏-魏*,手机号脱敏-187**

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



