Java 数据加密解密及脱敏处理
(一)实现效果 (注解自动加密解密)
(1) 解密 impl类加注解
返回VO实体类中加注释
(2) 加密 controller 解密注解 @Encryption
入参实体类 加密注解 @EncryptField
(3)也可以单独调用加密或解密
// 明文单独调用加密
String phoneNums = AesUtil.encryptString(phoneNum);
// 明文单独调用脱敏
s.setLegalPhone(AesUtil.desensitization(s.getLegalPhone(), DesensitizationEnum.phoneNum));
// 密文解密成明文单独调用
AesUtil.decryptString(query.getKeywords()))
加密、解密
加密DTO类
@EncryptField
加密Controller
@Encryption
解密加脱敏 VO类
@DecryptField(DesensitizationEnum.idCard)
解密明文
@DecryptField(DesensitizationEnum.isPlaintext)
解密Controller
@Decryption
(4) 前端显示解密脱敏效果
(5) 数据库字段加密后效果
(二) 准备基础类
(1) 拦截需解密注解类 DecryptAspect
@Slf4j
@Aspect
@Component
public class DecryptAspect {
//拦截需解密注解
@Pointcut("@annotation(com.wangyao.remote.desensitization.Decryption)")
public void point() {
}
@Around("point()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//解密
return decrypt(joinPoint);
}
public Object decrypt(ProceedingJoinPoint joinPoint) {
Object result = null;
try {
Object obj = joinPoint.proceed();
if (obj != null) {
//可自行扩展其他类型字段的判断
if (obj instanceof String) {
decryptValue();
}else if(obj instanceof ArrayList) {
decryptList(obj);
result = obj;
}else if(obj instanceof ServerResponseEntity){
if(((ServerResponseEntity<?>) obj).getData() instanceof PageVO) {
List<?> items = ((PageVO<?>) ((ServerResponseEntity<?>) obj).getData()).getList();
Object s = decryptData(items);
JSON.parseArray( JSON.toJSONString(s), ((PageVO<?>) ((ServerResponseEntity<?>) obj).getData()).getList().getClass());
result = obj;
} else if(((ServerResponseEntity<?>) obj).getData() instanceof EsPageVO){
List<?> items = ((EsPageVO<?>) ((ServerResponseEntity<?>) obj).getData()).getList();
Object s = decryptData(items);
JSON.parseArray( JSON.toJSONString(s), ((EsPageVO<?>) ((ServerResponseEntity<?>) obj).getData()).getList().getClass());
result = obj;
} else {
Object s = decryptData(((ServerResponseEntity<?>) obj).getData());
JSON.parseArray( JSON.toJSONString(s), (((ServerResponseEntity<?>) obj).getData()).getClass());
result = obj;
}
}else if(obj instanceof PageVO){
List<?> items = ((PageVO<?>) (obj)).getList();
Object s = decryptData(items);
JSON.parseArray( JSON.toJSONString(s), ((PageVO<?>) (obj)).getList().getClass());
result = obj;
}else if(obj instanceof List){
List<?> items =(List)(obj);
Object s = decryptData(items);
JSON.parseArray( JSON.toJSONString(s), ((List) (obj)).getClass());
result = obj;
}else {
result = decryptData(obj);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
private Object decryptData(Object obj) throws IllegalAccessException {
if (Objects.isNull(obj)) {
return null;
}
if (obj instanceof ArrayList) {
decryptList(obj);
}else {
decryptObj(obj);
}
return obj;
}
private void decryptObj(Object obj) throws IllegalAccessException {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
boolean hasSecureField = field.isAnnotationPresent(DecryptField.class);
if (hasSecureField) {
field.setAccessible(true);
if (field.get(obj) != null) {
String realValue = (String) field.get(obj);
if(realValue.length()>30){
DesensitizationEnum desensitizationEnum = field.getAnnotation(DecryptField.class).value();
String value = (String) AesUtil.decrypt(realValue,desensitizationEnum);
field.set(obj, value);
}else {
field.set(obj, realValue);
}
}
}
}
}
private void decryptList(Object obj) throws IllegalAccessException {
List<Object> result = new ArrayList<>();
if (obj instanceof ArrayList) {
result.addAll((Collection<?>) obj);
}
for (Object object : result) {
decryptObj(object);
}
}
private void decryptValue() {
log.info("根据对象进行解密脱敏,单个字段不做处理!");
}
}
(2) 数据脱敏注解类(用在实体类上) DecryptField
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptField {
DesensitizationEnum value();
}
(3) 解密 注解类 (用在方法上) Decryption
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Decryption {
}
(4) 脱敏枚举 DesensitizationEnum
public enum DesensitizationEnum {
/**
* 明文 不隐藏
*/
isPlaintext,
/**
* 通用 前3 后2 其他隐藏
*/
current,
/**
* 手机号
*/
phoneNum,
/**
* 地址
*/
address,
/**
* 身份证号
*/
idCard,
/**
* 银行卡号
*/
bankCard,
/**
* 名称
*/
name,
/**
* 邮箱
*/
email,
}
(5) 脱敏实现类 DesensitizationUtil
public class DesensitizationUtil {
public static Object desensitization(Object obj, DesensitizationEnum desensitizationEnum) {
Object result;
switch (desensitizationEnum) {
case name:
result = strUtilHide(obj, 1);
break;
case address:
result = strUtilHide(obj, 3);
break;
case phoneNum:
result = mobilePhone((String)obj);
break;
case idCard:
result = idCardNum((String)obj);
break;
case current: // 通用
result = current((String)obj);
break;
case isPlaintext: // 明文
result = (String)obj;
break;
default:
result = "";
}
return result;
}
/**
* start从0开始
*/
public static Object strUtilHide(String obj, int start, int end) {
return StrUtil.hide(obj, start, end);
}
public static Object strUtilHide(Object obj, int start) {
return strUtilHide(((String) obj), start, ((String) obj).length());
}
/**
* 对字符串进行脱敏操作
*
* @param origin 原始字符串
* @param prefixNoMaskLen 左侧需要保留几位明文字段
* @param suffixNoMaskLen 右侧需要保留几位明文字段
* @param maskStr 用于遮罩的字符串, 如'*'
* @return 脱敏后结果
*/
public static String desValue(String origin, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) {
if (origin == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0, n = origin.length(); i < n; i++) {
if (i < prefixNoMaskLen) {
sb.append(origin.charAt(i));
continue;
}
if (i > (n - suffixNoMaskLen - 1)) {
sb.append(origin.charAt(i));
continue;
}
sb.append(maskStr);
}
return sb.toString();
}
/**
* 【中文姓名】只显示最后一个汉字,其他隐藏为星号,比如:**梦
*
* @param fullName 姓名
* @return 结果
*/
public static String chineseName(String fullName) {
if (fullName == null) {
return null;
}
return desValue(fullName, 1, 0, "*");
}
/**
* 【身份证号】显示前4位, 后2位,其他隐藏。
*
* @param id 身份证号码
* @return 结果
*/
public static String idCardNum(String id) {
return desValue(id, 4, 2, "*");
}
/**
* 【手机号码】前三位,后四位,其他隐藏。
*
* @param num 手机号码
* @return 结果
*/
public static String mobilePhone(String num) {
return desValue(num, 3, 4, "*");
}
/**
* 通用 前3 后2 其他隐藏
*/
public static String current(String num) {
return desValue(num, 3, 2, "*");
}
}
(6) 拦截需加密注解 类 EncryptAspect
@Slf4j
@Aspect
@Component
public class EncryptAspect {
//拦截需加密注解
@Pointcut("@annotation(com.wangyao.remote.desensitization.Encryption)")
public void point() {
}
@Around("point()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//加密
encrypt(joinPoint);
return joinPoint.proceed();
}
public void encrypt(ProceedingJoinPoint joinPoint) {
Object[] objects;
try {
objects = joinPoint.getArgs();
if (objects.length != 0) {
for (Object object : objects) {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(EncryptField.class)) {
field.setAccessible(true);
if (field.get(object) != null) {
// 进行加密
Object encrypt = AesUtil.encrypt(field.get(object));
field.set(object, encrypt);
}
}
}
}
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
(7) 数据加密 注解(用在实体类上) EncryptField
@Target(ElementType.FIELD) //FIELD 说明该注解只能用在字段上
@Retention(RetentionPolicy.RUNTIME) //RUNTIME 说明该注解在运行时生效
public @interface EncryptField {
}
(8) 方法解密(用在方法上)
// METHOD 说明该注解只能用在方法上
// RUNTIME 说明该注解在运行时生效
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Encryption {
}
(三) 加密方法 AES
public class AesUtil {
// 默认16位 或 128 256位
// public static String AES_KEY = "AWk#SqerdSSfdsSShbSd910";
// public static AES aes = SecureUtil.aes(AES_KEY.getBytes());
public static AES aes = SecureUtil.aes("AWk#qerdfdshbd910".getBytes());
public static Object encrypt(Object obj) {
return aes.encryptHex((String) obj);
}
public static Object decrypt(Object obj, DesensitizationEnum desensitizationEnum) {
// 解密
Object decrypt = decrypt(obj);
// 脱敏
return DesensitizationUtil.desensitization(decrypt, desensitizationEnum);
}
public static Object decrypt(Object obj) {
return aes.decryptStr((String) obj, CharsetUtil.CHARSET_UTF_8);
}
// 加密
public static String encryptString(String str) {
return aes.encryptHex(str);
}
// 解密
public static String decryptString(String str) {
return aes.decryptStr(str, CharsetUtil.CHARSET_UTF_8);
}
// 解密+脱敏 返回字符串
public static String decryptStringDesensitization(String str, DesensitizationEnum desensitizationEnum) {
// 解密
String decrypt = decryptString(str);
// 脱敏
Object object = decrypt;
return DesensitizationUtil.desensitization(object, desensitizationEnum).toString();
}
// 字符串脱敏
public static String desensitization(String str, DesensitizationEnum desensitizationEnum) {
// 脱敏
return DesensitizationUtil.desensitization(str, desensitizationEnum).toString();
}
// 加密集合
public static List<String> encryptStringList(List<String> str) {
return str.stream().map(m->aes.encryptHex(m)).collect(Collectors.toList());
}
// 判断是否包含中文
public static boolean containsChineseCharacters(String str) {
if (str == null) {
return false;
}
return str.chars().anyMatch(c -> isChineseCharacter((char) c));
}
public static boolean isChineseCharacter(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION;
}
public static void main(String[] args) {
String s = "d2528630b2ccbd3f12c979e0cc2754f3";
System.out.println(decryptString(s));
}
}