AOP 实现数据脱敏加解密

1.脱敏字段枚举

/**
 * 脱敏字段枚举
 */
public enum DeIdentificationEnum {
    PHONE_NO,
    IDENTIFICATION_NO;
}

2.自定义加解密注解

2.1 加密注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
}

2.2

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
    //

    DeIdentificationEnum value();
}

2.3解密注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Decrypt {
}

2.4

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptField {
    //脱敏
   
    DeIdentificationEnum value();
}

3.包含加密字段的实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class UserDTO {
    private String name;
    private String address;
    @EncryptField(DesensitiveEnum.PHONE)
    @DecryptField(DesensitiveEnum.PHONE)
    private String phone;
}

4.自定义切面实现加解密和脱敏逻辑

@Aspect
@Component
@Slf4j
public class EncryptAspect {

    @Autowired
    SfEncryptService sfEncryptService;

    @Pointcut("@annotation(com.Encrypt)")
    public void encryptPointCut() {
    }

    @Pointcut("@annotation(com.annotation.Decrypt)")
    public void decryptPointCut() {
    }

    /**
     * 解密
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("decryptPointCut()")
    public Object decryptMethodAop(ProceedingJoinPoint joinPoint) throws Throwable{
        Object proceed = joinPoint.proceed();
        if (proceed instanceof UserDTO) {
            Field[] fields = proceed.getClass().getDeclaredFields();
            Arrays.stream(fields).forEach(field -> {

                if (field.isAnnotationPresent(DecryptField.class))
                {
                    DecryptField annotation = field.getAnnotation(DecryptField.class);

                    DesensitiveEnum value = annotation.value();
                    if (value.equals(DesensitiveEnum.PHONE)){
                        String phone = ((UserDTO) proceed).getPhone();
                        try {
                            String decryptPhoneNo = decryptPhoneNo(phone);
                            log.info("被解密的手机号{}",decryptPhoneNo);
                            //解密后脱敏
                            String deSensitivePhoneNo = decryptPhoneNo.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
                            ((UserDTO) proceed).setPhone(deSensitivePhoneNo);
                            log.info("脱敏手机号:{}",deSensitivePhoneNo);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

        }

        return proceed;
    }
 private String decryptPhoneNo(String phone) {
  
      String decryptPhone = null;

    //解密逻辑
    return decryptPhone;
}
    /**
     * 加密
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("encryptPointCut()")
    public Object encryptMethodAop(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        if (args.length !=0) {
            Arrays.stream(args).forEach(obj->{
                if (obj instanceof UserDTO){
                    Field[] fields = obj.getClass().getDeclaredFields();
                    Arrays.stream(fields).forEach(field -> {
                        if (field.isAnnotationPresent(EncryptField.class)) {
                            EncryptField annotation = field.getAnnotation(EncryptField.class);
                            DesensitiveEnum value = annotation.value();

                            switch (value) {
                                case PHONE:
                                    String encryptPhoneNo = null;
                                    try {
                                        encryptPhoneNo = encryptPhoneNo((((UserDTO) obj).getPhone()));
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    ((UserDTO) obj).setPhone(encryptPhoneNo);
                                    break;
                                default:
                                    throw new RuntimeException("不匹配的加密字段");

                            }
                        }
                    });
                }
            });
        }

        return joinPoint.proceed();
    }

private String encryptPhoneNo(String phoneNo) {

String encryptPhone=null;
   //解密逻辑
return encryptPhone;
}

}

模拟测试

@RestController
@Slf4j
@RequestMapping("/enTest")
public class CFCAController {
    @Autowired
    CFCAService service;


    @RequestMapping(value = "/getUserTest",method = RequestMethod.GET)
    @Encrypt
    public UserDTO getUserTes(){
        UserDTO userDTO = new UserDTO().setAddress("蓬莱").setName("菩萨").setPhone("12345678901");
        return userDTO;
    }

    @RequestMapping(value = "/createUser",method = RequestMethod.POST)
    @Encrypt
    public String createUser(@RequestBody UserDTO userDTO) {
        log.info("用户数据落库:{}",userDTO.toString());
        return "200";
    }

    @RequestMapping(value = "/getUser",method = RequestMethod.GET)
    @Decrypt
    public UserDTO getUser(){
        UserDTO userDTO = new UserDTO().setAddress("蓬莱").setName("菩萨").setPhone("DEEQAVTsfXfRmAAm11aN7Ux1HiYfI%3D");
        return userDTO;

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,针对您的问题,我可以给您一些简单的解释。 SpringBoot中的AOP(面向切面编程)可以帮助我们对方法进行拦截和增强,这样我们就可以在方法执行前后进行一些自己想要的操作,比如接口的请求数据解密和返回数据加密。 具体来说,我们可以通过定义一个切面类,在其中定义一个前置通知和一个后置通知。前置通知可以在方法执行前进行解密操作,后置通知可以在方法执行后进行加密操作。 下面是一个简单的示例代码: ```java @Aspect @Component public class EncryptAspect { @Autowired private EncryptService encryptService; @Pointcut("execution(public * com.example.controller.*.*(..))") public void encrypt() {} @Before("encrypt()") public void doEncrypt(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); for (Object arg : args) { if (arg instanceof String) { String decrypted = encryptService.decrypt((String) arg); // 将解密后的数据重新设置到参数中 // ... } } } @AfterReturning(value = "encrypt()", returning = "result") public void doDecrypt(JoinPoint joinPoint, Object result) { if (result instanceof String) { String encrypted = encryptService.encrypt((String) result); // 将加密后的数据返回 // ... } } } ``` 在上面的示例代码中,我们定义了一个切面类`EncryptAspect`,其中通过`@Pointcut`注解定义了需要拦截的方法,即`com.example.controller`包下的所有方法。在`doEncrypt`方法中,我们可以获取到方法的参数,并进行解密操作;在`doDecrypt`方法中,我们可以获取到方法的返回值,并进行加密操作。 需要注意的是,上面的示例代码中的`EncryptService`是一个加解密服务的接口,具体的加解密实现可以根据自己的需求进行编写。 希望以上解释可以帮助到您。如果还有其他问题,欢迎随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值