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;
}