数据脱敏sensitive(前端或数据库加密,解密)

编程入门 行业动态 更新时间:2024-10-10 02:16:41

数据脱敏sensitive(前端或<a href=https://www.elefans.com/category/jswz/34/1771350.html style=数据库加密,解密)"/>

数据脱敏sensitive(前端或数据库加密,解密)

可以对数据加密,解密,对数据库加密的数据进行解密显示,对数据库没有加密的数据进行加密处理展示前端等待

1:引入数据如下结构

1-1:SensitiveDecode脱敏解密注解

package com.example.poi.desensitization.annotation;import java.lang.annotation.*;/*** 脱敏解密注解* @Author xu* @create 2023/9/4 19*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SensitiveDecode {/*** 指明需要脱敏的实体类class* @return*/Class entity() default Object.class;
}

1-2:SensitiveEncode脱敏加密注解

package com.example.poi.desensitization.annotation;import java.lang.annotation.*;/*** 脱敏加密注解* @Author xu* @create 2023/9/4 19*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SensitiveEncode {/*** 指明需要脱敏的实体类class* @return*/Class entity() default Object.class;
}

1-3:SensitiveField字段注解

package com.example.poi.desensitization.annotation;import com.example.poi.desensitization.enums.SensitiveEnum;import java.lang.annotation.*;/*** 字段上定义,标识字段存储的信息是敏感的* @Author xu* @create 2023/9/4 19*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SensitiveField {/*** 不同类型处理不同* @return*/SensitiveEnum type() default SensitiveEnum.ENCODE;
}

1-4:SensitiveDataAspect敏感数据切面处理类

package com.example.poi.desensitization.aspect;import com.example.poi.desensitization.annotation.SensitiveDecode;
import com.example.poi.desensitization.annotation.SensitiveEncode;
import com.example.poi.desensitization.utils.SensitiveInfoUtil;
import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.List;/*** 敏感数据切面处理类* @Author xu* @create 2023/9/4 20*/
@Slf4j
@Aspect
@Component
public class SensitiveDataAspect {/*** 定义切点Pointcut*/@Pointcut("@annotation(com.example.poi.desensitization.annotation.SensitiveEncode) || @annotation(com.example.poi.desensitization.annotation.SensitiveDecode)")public void sensitivePointCut() {}@Around("sensitivePointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {// 处理结果Object result = point.proceed();if(result == null){return result;}Class resultClass = result.getClass();log.debug(" resultClass  = {}" , resultClass);if(resultClass.isPrimitive()){//是基本类型 直接返回 不需要处理return result;}// 获取方法注解信息:是哪个实体、是加密还是解密boolean isEncode = true;Class entity = null;MethodSignature methodSignature = (MethodSignature) point.getSignature();Method method = methodSignature.getMethod();SensitiveEncode encode = method.getAnnotation(SensitiveEncode.class);if(encode==null){SensitiveDecode decode = method.getAnnotation(SensitiveDecode.class);if(decode!=null){entity = decode.entity();isEncode = false;}}else{entity = encode.entity();}long startTime=System.currentTimeMillis();if(resultClass.equals(entity) || entity.equals(Object.class)){// 方法返回实体和注解的entity一样,如果注解没有申明entity属性则认为是(方法返回实体和注解的entity一样)SensitiveInfoUtil.handlerObject(result, isEncode);} else if(result instanceof List){// 方法返回List<实体>SensitiveInfoUtil.handleList(result, entity, isEncode);}else{// 方法返回一个对象SensitiveInfoUtil.handleNestedObject(result, entity, isEncode);}long endTime=System.currentTimeMillis();log.info((isEncode ? "加密操作," : "解密操作,") + "Aspect程序耗时:" + (endTime - startTime) + "ms");return result;}}

1-5:SensitiveEnum

package com.example.poi.desensitization.enums;/*** 敏感字段信息类型* @Author xu* @create 2023/9/4 19*/
public enum SensitiveEnum {/*** 加密*/ENCODE,/*** 中文名*/CHINESE_NAME,/*** 身份证号*/ID_CARD,/*** 座机号*/FIXED_PHONE,/*** 手机号*/MOBILE_PHONE,/*** 地址*/ADDRESS,/*** 电子邮件*/EMAIL,/*** 银行卡*/BANK_CARD,/*** 公司开户银行联号*/CNAPS_CODE;}

1-6:AesEncryptUtil加密工具类

package com.example.poi.desensitization.utils.encryption;import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
//import org.apache.shiro.codec.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;/*** @Description: AES 加密* @Author xu* @create 2023/9/4 19*/
public class AesEncryptUtil {/*** 使用AES-128-CBC加密模式 key和iv可以相同*/private static String KEY = EncryptedString.key;private static String IV = EncryptedString.iv;/*** 加密方法* @param data  要加密的数据* @param key 加密key* @param iv 加密iv* @return 加密的结果* @throws Exception*/public static String encrypt(String data, String key, String iv) throws Exception {try {//"算法/模式/补码方式"NoPadding PkcsPaddingCipher cipher = Cipher.getInstance("AES/CBC/NoPadding");int blockSize = cipher.getBlockSize();byte[] dataBytes = data.getBytes();int plaintextLength = dataBytes.length;if (plaintextLength % blockSize != 0) {plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));}byte[] plaintext = new byte[plaintextLength];System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);byte[] encrypted = cipher.doFinal(plaintext);return Base64.encode(encrypted);//return Base64.encodeToString(encrypted);} catch (Exception e) {e.printStackTrace();return null;}}/*** 解密方法* @param data 要解密的数据* @param key  解密key* @param iv 解密iv* @return 解密的结果* @throws Exception*/public static String desEncrypt(String data, String key, String iv) throws Exception {//update-begin-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理byte[] encrypted1 = Base64.decode(data);Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);byte[] original = cipher.doFinal(encrypted1);String originalString = new String(original);//加密解码后的字符串会出现\u0000return originalString.replaceAll("\\u0000", "");//update-end-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理}/*** 使用默认的key和iv加密* @param data* @return* @throws Exception*/public static String encrypt(String data) throws Exception {return encrypt(data, KEY, IV);}/*** 使用默认的key和iv解密* @param data* @return* @throws Exception*/public static String desEncrypt(String data) throws Exception {return desEncrypt(data, KEY, IV);}/*** 测试*/public static void main(String args[]) throws Exception {String test1 = "sa";String test =new String(test1.getBytes(),"UTF-8");String data = "4I80+jJsZ/aR+n+MsRd7qw==";String key =  KEY;String iv = IV;String jiemi =desEncrypt(data, key, iv).trim();System.out.println("解密:"+jiemi);String aa="1234567897891";String encrypt = SecureUtil.aes(key.getBytes()).encryptBase64(aa);String s = SecureUtil.aes(key.getBytes()).decryptStr(encrypt);System.out.println("");}
}

1-7:EncryptedString

package com.example.poi.desensitization.utils.encryption;import lombok.Data;/*** 秘钥和偏移量* @Author xu* @create 2023/9/4 19*/
@Data
public class EncryptedString {/*** 长度为16个字符*/public static  String key = "1234567890adbcde";/*** 长度为16个字符*/public static  String iv  = "1234567890hjlkew";
}

1-8:CommonConstant通用常量

package com.example.poi.desensitization.utils;/*** @Description: 通用常量* @Author xu* @create 2023/9/4 19*/
public interface CommonConstant {/*** 未知的*/String UNKNOWN = "unknown";/*** String 类型的空值*/String STRING_NULL = "null";}

1-9:oConvertUtils

package com.example.poi.desensitization.utils;import lombok.extern.slf4j.Slf4j;import org.apachemons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.InetAddress;
import java.NetworkInterface;
import java.SocketException;
import java.UnknownHostException;
import java.sql.Date;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Slf4j
public class oConvertUtils {public static boolean isEmpty(Object object) {if (object == null) {return (true);}if ("".equals(object)) {return (true);}if (CommonConstant.STRING_NULL.equals(object)) {return (true);}return (false);}public static boolean isNotEmpty(Object object) {if (object != null && !"".equals(object) && !object.equals(CommonConstant.STRING_NULL)) {return (true);}return (false);}public static String decode(String strIn, String sourceCode, String targetCode) {String temp = code2code(strIn, sourceCode, targetCode);return temp;}@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")public static String StrToUTF(String strIn, String sourceCode, String targetCode) {strIn = "";try {strIn = new String(strIn.getBytes("ISO-8859-1"), "GBK");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}return strIn;}private static String code2code(String strIn, String sourceCode, String targetCode) {String strOut = null;if (strIn == null || "".equals(strIn.trim())) {return strIn;}try {byte[] b = strIn.getBytes(sourceCode);for (int i = 0; i < b.length; i++) {System.out.print(b[i] + "  ");}strOut = new String(b, targetCode);} catch (Exception e) {e.printStackTrace();return null;}return strOut;}public static int getInt(String s, int defval) {if (s == null || s == "") {return (defval);}try {return (Integer.parseInt(s));} catch (NumberFormatException e) {return (defval);}}public static int getInt(String s) {if (s == null || s == "") {return 0;}try {return (Integer.parseInt(s));} catch (NumberFormatException e) {return 0;}}public static int getInt(String s, Integer df) {if (s == null || s == "") {return df;}try {return (Integer.parseInt(s));} catch (NumberFormatException e) {return 0;}}public static Integer[] getInts(String[] s) {if (s == null) {return null;}Integer[] integer = new Integer[s.length];for (int i = 0; i < s.length; i++) {integer[i] = Integer.parseInt(s[i]);}return integer;}public static double getDouble(String s, double defval) {if (s == null || s == "") {return (defval);}try {return (Double.parseDouble(s));} catch (NumberFormatException e) {return (defval);}}public static double getDou(Double s, double defval) {if (s == null) {return (defval);}return s;}/*public static Short getShort(String s) {if (StringUtil.isNotEmpty(s)) {return (Short.parseShort(s));} else {return null;}}*/public static int getInt(Object object, int defval) {if (isEmpty(object)) {return (defval);}try {return (Integer.parseInt(object.toString()));} catch (NumberFormatException e) {return (defval);}}public static Integer getInt(Object object) {if (isEmpty(object)) {return null;}try {return (Integer.parseInt(object.toString()));} catch (NumberFormatException e) {return null;}}public static int getInt(BigDecimal s, int defval) {if (s == null) {return (defval);}return s.intValue();}public static Integer[] getIntegerArry(String[] object) {int len = object.length;Integer[] result = new Integer[len];try {for (int i = 0; i < len; i++) {result[i] = new Integer(object[i].trim());}return result;} catch (NumberFormatException e) {return null;}}public static String getString(String s) {return (getString(s, ""));}/*** 转义成Unicode编码* @param s* @return*//*public static String escapeJava(Object s) {return StringEscapeUtils.escapeJava(getString(s));}*/public static String getString(Object object) {if (isEmpty(object)) {return "";}return (object.toString().trim());}public static String getString(int i) {return (String.valueOf(i));}public static String getString(float i) {return (String.valueOf(i));}public static String getString(String s, String defval) {if (isEmpty(s)) {return (defval);}return (s.trim());}public static String getString(Object s, String defval) {if (isEmpty(s)) {return (defval);}return (s.toString().trim());}public static long stringToLong(String str) {Long test = new Long(0);try {test = Long.valueOf(str);} catch (Exception e) {}return test.longValue();}/*** 获取本机IP*/public static String getIp() {String ip = null;try {InetAddress address = InetAddress.getLocalHost();ip = address.getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}return ip;}/*** 判断一个类是否为基本数据类型。* * @param clazz*            要判断的类。* @return true 表示为基本数据类型。*/private static boolean isBaseDataType(Class clazz) throws Exception {return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class) || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz.isPrimitive());}/*** @param request*            IP* @return IP Address*/public static String getIpAddrByRequest(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || CommonConstant.UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || CommonConstant.UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || CommonConstant.UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}/*** @return 本机IP* @throws SocketException*/public static String getRealIp() throws SocketException {// 本地IP,如果没有配置外网IP则返回它String localip = null;// 外网IPString netip = null;Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();InetAddress ip = null;// 是否找到外网IPboolean finded = false;while (netInterfaces.hasMoreElements() && !finded) {NetworkInterface ni = netInterfaces.nextElement();Enumeration<InetAddress> address = ni.getInetAddresses();while (address.hasMoreElements()) {ip = address.nextElement();// 外网IPif (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {netip = ip.getHostAddress();finded = true;break;} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 内网IPlocalip = ip.getHostAddress();}}}if (netip != null && !"".equals(netip)) {return netip;} else {return localip;}}/*** java去除字符串中的空格、回车、换行符、制表符* * @param str* @return*/public static String replaceBlank(String str) {String dest = "";if (str != null) {String reg = "\\s*|\t|\r|\n";Pattern p = Patternpile(reg);Matcher m = p.matcher(str);dest = m.replaceAll("");}return dest;}/*** 判断元素是否在数组内* * @param substring* @param source* @return*/public static boolean isIn(String substring, String[] source) {if (source == null || source.length == 0) {return false;}for (int i = 0; i < source.length; i++) {String aSource = source[i];if (aSource.equals(substring)) {return true;}}return false;}/*** 获取Map对象*/public static Map<Object, Object> getHashMap() {return new HashMap<>(5);}/*** SET转换MAP* * @param str* @return*/public static Map<Object, Object> setToMap(Set<Object> setobj) {Map<Object, Object> map = getHashMap();for (Iterator iterator = setobj.iterator(); iterator.hasNext();) {Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) iterator.next();map.put(entry.getKey().toString(), entry.getValue() == null ? "" : entry.getValue().toString().trim());}return map;}public static boolean isInnerIp(String ipAddress) {boolean isInnerIp = false;long ipNum = getIpNum(ipAddress);/*** 私有IP:A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类 192.168.0.0-192.168.255.255 当然,还有127这个网段是环回地址**/long aBegin = getIpNum("10.0.0.0");long aEnd = getIpNum("10.255.255.255");long bBegin = getIpNum("172.16.0.0");long bEnd = getIpNum("172.31.255.255");long cBegin = getIpNum("192.168.0.0");long cEnd = getIpNum("192.168.255.255");String localIp = "127.0.0.1";isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || localIp.equals(ipAddress);return isInnerIp;}private static long getIpNum(String ipAddress) {String[] ip = ipAddress.split("\\.");long a = Integer.parseInt(ip[0]);long b = Integer.parseInt(ip[1]);long c = Integer.parseInt(ip[2]);long d = Integer.parseInt(ip[3]);long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;return ipNum;}private static boolean isInner(long userIp, long begin, long end) {return (userIp >= begin) && (userIp <= end);}/*** 将下划线大写方式命名的字符串转换为驼峰式。* 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br>* 例如:hello_world->helloWorld* * @param name*            转换前的下划线大写方式命名的字符串* @return 转换后的驼峰式命名的字符串*/public static String camelName(String name) {StringBuilder result = new StringBuilder();// 快速检查if (name == null || name.isEmpty()) {// 没必要转换return "";} else if (!name.contains(SymbolConstant.UNDERLINE)) {// 不含下划线,仅将首字母小写//update-begin--Author:zhoujf  Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能//update-begin--Author:zhoujf  Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能return name.substring(0, 1).toLowerCase() + name.substring(1).toLowerCase();//update-end--Author:zhoujf  Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能}// 用下划线将原始字符串分割String[] camels = name.split("_");for (String camel : camels) {// 跳过原始字符串中开头、结尾的下换线或双重下划线if (camel.isEmpty()) {continue;}// 处理真正的驼峰片段if (result.length() == 0) {// 第一个驼峰片段,全部字母都小写result.append(camel.toLowerCase());} else {// 其他的驼峰片段,首字母大写result.append(camel.substring(0, 1).toUpperCase());result.append(camel.substring(1).toLowerCase());}}return result.toString();}/*** 将下划线大写方式命名的字符串转换为驼峰式。* 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br>* 例如:hello_world,test_id->helloWorld,testId* * @param names*            转换前的下划线大写方式命名的字符串* @return 转换后的驼峰式命名的字符串*/public static String camelNames(String names) {if(names==null||"".equals(names)){return null;}StringBuffer sf = new StringBuffer();String[] fs = names.split(",");for (String field : fs) {field = camelName(field);sf.append(field + ",");}String result = sf.toString();return result.substring(0, result.length() - 1);}//update-begin--Author:zhoujf  Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能/*** 将下划线大写方式命名的字符串转换为驼峰式。(首字母写)* 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br>* 例如:hello_world->HelloWorld* * @param name*            转换前的下划线大写方式命名的字符串* @return 转换后的驼峰式命名的字符串*/public static String camelNameCapFirst(String name) {StringBuilder result = new StringBuilder();// 快速检查if (name == null || name.isEmpty()) {// 没必要转换return "";} else if (!name.contains(SymbolConstant.UNDERLINE)) {// 不含下划线,仅将首字母小写return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase();}// 用下划线将原始字符串分割String[] camels = name.split("_");for (String camel : camels) {// 跳过原始字符串中开头、结尾的下换线或双重下划线if (camel.isEmpty()) {continue;}// 其他的驼峰片段,首字母大写result.append(camel.substring(0, 1).toUpperCase());result.append(camel.substring(1).toLowerCase());}return result.toString();}//update-end--Author:zhoujf  Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能/*** 将驼峰命名转化成下划线* @param para* @return*/public static String camelToUnderline(String para){int length = 3;if(para.length()<length){return para.toLowerCase(); }StringBuilder sb=new StringBuilder(para);//定位int temp=0;//从第三个字符开始 避免命名不规范 for(int i=2;i<para.length();i++){if(Character.isUpperCase(para.charAt(i))){sb.insert(i+temp, "_");temp+=1;}}return sb.toString().toLowerCase(); }/*** 随机数* @param place 定义随机数的位数*/public static String randomGen(int place) {String base = "qwertyuioplkjhgfdsazxcvbnmQAZWSXEDCRFVTGBYHNUJMIKLOP0123456789";StringBuffer sb = new StringBuffer();Random rd = new Random();for(int i=0;i<place;i++) {sb.append(base.charAt(rd.nextInt(base.length())));}return sb.toString();}/*** 获取类的所有属性,包括父类* * @param object* @return*/public static Field[] getAllFields(Object object) {Class<?> clazz = object.getClass();List<Field> fieldList = new ArrayList<>();while (clazz != null) {fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));clazz = clazz.getSuperclass();}Field[] fields = new Field[fieldList.size()];fieldList.toArray(fields);return fields;}/*** 将map的key全部转成小写* @param list* @return*/public static List<Map<String, Object>> toLowerCasePageList(List<Map<String, Object>> list){List<Map<String, Object>> select = new ArrayList<>();for (Map<String, Object> row : list) {Map<String, Object> resultMap = new HashMap<>(5);Set<String> keySet = row.keySet(); for (String key : keySet) { String newKey = key.toLowerCase(); resultMap.put(newKey, row.get(key)); }select.add(resultMap);}return select;}/*** 将entityList转换成modelList* @param fromList* @param tClass* @param <F>* @param <T>* @return*/public static<F,T> List<T> entityListToModelList(List<F> fromList, Class<T> tClass){if(fromList == null || fromList.isEmpty()){return null;}List<T> tList = new ArrayList<>();for(F f : fromList){T t = entityToModel(f, tClass);tList.add(t);}return tList;}public static<F,T> T entityToModel(F entity, Class<T> modelClass) {log.debug("entityToModel : Entity属性的值赋值到Model");Object model = null;if (entity == null || modelClass ==null) {return null;}try {model = modelClass.newInstance();} catch (InstantiationException e) {log.error("entityToModel : 实例化异常", e);} catch (IllegalAccessException e) {log.error("entityToModel : 安全权限异常", e);}BeanUtils.copyProperties(entity, model);return (T)model;}/*** 判断 list 是否为空** @param list* @return true or false* list == null		: true* list.size() == 0	: true*/public static boolean listIsEmpty(Collection list) {return (list == null || list.size() == 0);}/*** 判断 list 是否不为空** @param list* @return true or false* list == null		: false* list.size() == 0	: false*/public static boolean listIsNotEmpty(Collection list) {return !listIsEmpty(list);}/*** 读取静态文本内容* @param url* @return*/public static String readStatic(String url) {String json = "";try {//换个写法,解决springboot读取jar包中文件的问题InputStream stream = oConvertUtils.class.getClassLoader().getResourceAsStream(url.replace("classpath:", ""));json = IOUtils.toString(stream,"UTF-8");} catch (IOException e) {log.error(e.getMessage(),e);}return json;}
}

1-10:SensitiveInfoUtil

package com.example.poi.desensitization.utils;import com.example.poi.desensitization.enums.SensitiveEnum;
import com.example.poi.desensitization.annotation.SensitiveField;
import com.example.poi.desensitization.utils.encryption.AesEncryptUtil;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.List;/*** @Author xu* @create 2023/9/4 20*/
@Slf4j
public class SensitiveInfoUtil {/*** 处理嵌套对象* @param obj 方法返回值* @param entity 实体class* @param isEncode 是否加密(true: 加密操作 / false:解密操作)* @throws IllegalAccessException*/public static void handleNestedObject(Object obj, Class entity, boolean isEncode) throws IllegalAccessException {Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {if(field.getType().isPrimitive()){continue;}if(field.getType().equals(entity)){// 对象里面是实体field.setAccessible(true);Object nestedObject = field.get(obj);handlerObject(nestedObject, isEncode);break;}else{// 对象里面是List<实体>if(field.getGenericType() instanceof ParameterizedType){ParameterizedType pt = (ParameterizedType)field.getGenericType();if(pt.getRawType().equals(List.class)){if(pt.getActualTypeArguments()[0].equals(entity)){field.setAccessible(true);Object nestedObject = field.get(obj);handleList(nestedObject, entity, isEncode);break;}}}}}}/*** 处理Object* @param obj 方法返回值* @param isEncode 是否加密(true: 加密操作 / false:解密操作)* @return* @throws IllegalAccessException*/public static Object handlerObject(Object obj, boolean isEncode) throws IllegalAccessException {log.debug(" obj --> "+ obj.toString());long startTime=System.currentTimeMillis();if (oConvertUtils.isEmpty(obj)) {return obj;}// 判断是不是一个对象Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {boolean isSensitiveField = field.isAnnotationPresent(SensitiveField.class);if(isSensitiveField){// 必须有SensitiveField注解 才作处理if(field.getType().isAssignableFrom(String.class)){//必须是字符串类型 才作处理field.setAccessible(true);String realValue = (String) field.get(obj);if(realValue==null || "".equals(realValue)){continue;}SensitiveField sf = field.getAnnotation(SensitiveField.class);if(isEncode==true){//加密String value = SensitiveInfoUtil.getEncodeData(realValue,  sf.type());field.set(obj, value);}else{//解密只处理 encode类型的if(sf.type().equals(SensitiveEnum.ENCODE)){String value = SensitiveInfoUtil.getDecodeData(realValue);field.set(obj, value);}}}}}//long endTime=System.currentTimeMillis();//log.info((isEncode ? "加密操作," : "解密操作,") + "当前程序耗时:" + (endTime - startTime) + "ms");return obj;}/*** 处理 List<实体>* @param obj* @param entity* @param isEncode(true: 加密操作 / false:解密操作)*/public static void handleList(Object obj, Class entity, boolean isEncode){List list = (List)obj;if(list.size()>0){Object first = list.get(0);if(first.getClass().equals(entity)){for(int i=0; i<list.size(); i++){Object temp = list.get(i);try {handlerObject(temp, isEncode);} catch (IllegalAccessException e) {e.printStackTrace();}}}}}/*** 处理数据 获取解密后的数据* @param data* @return*/public static String getDecodeData(String data){String result = null;try {result = AesEncryptUtil.desEncrypt(data);} catch (Exception exception) {log.debug("数据解密错误,原数据:"+data);}//解决debug模式下,加解密失效导致中文被解密变成空的问题if(oConvertUtils.isEmpty(result) && oConvertUtils.isNotEmpty(data)){result = data;}return result;}/*** 处理数据 获取加密后的数据 或是格式化后的数据* @param data 字符串* @param sensitiveEnum 类型* @return 处理后的字符串*/public static String getEncodeData(String data, SensitiveEnum sensitiveEnum){String result;switch (sensitiveEnum){case ENCODE:try {result = AesEncryptUtil.encrypt(data);} catch (Exception exception) {log.error("数据加密错误", exception.getMessage());result = data;}break;case CHINESE_NAME:result = chineseName(data);break;case ID_CARD:result = idCardNum(data);break;case FIXED_PHONE:result = fixedPhone(data);break;case MOBILE_PHONE:result = mobilePhone(data);break;case ADDRESS:result = address(data, 3);break;case EMAIL:result = email(data);break;case BANK_CARD:result = bankCard(data);break;case CNAPS_CODE:result = cnapsCode(data);break;default:result = data;}return result;}/*** [中文姓名] 只显示第一个汉字,其他隐藏为2个星号* @param fullName 全名* @return <例子:李**>*/private static String chineseName(String fullName) {if (oConvertUtils.isEmpty(fullName)) {return "";}return formatRight(fullName, 1);}/*** [中文姓名] 只显示第一个汉字,其他隐藏为2个星号* @param familyName 姓* @param firstName 名* @return <例子:李**>*/private static String chineseName(String familyName, String firstName) {if (oConvertUtils.isEmpty(familyName) || oConvertUtils.isEmpty(firstName)) {return "";}return chineseName(familyName + firstName);}/*** [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。* @param id 身份证号* @return <例子:*************5762>*/private static String idCardNum(String id) {if (oConvertUtils.isEmpty(id)) {return "";}return formatLeft(id, 4);}/*** [固定电话] 后四位,其他隐藏* @param num 固定电话* @return <例子:****1234>*/private static String fixedPhone(String num) {if (oConvertUtils.isEmpty(num)) {return "";}return formatLeft(num, 4);}/*** [手机号码] 前三位,后四位,其他隐藏* @param num 手机号码* @return <例子:138******1234>*/private static String mobilePhone(String num) {if (oConvertUtils.isEmpty(num)) {return "";}int len = num.length();if(len<11){return num;}return formatBetween(num, 3, 4);}/*** [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护* @param address 地址* @param sensitiveSize 敏感信息长度* @return <例子:北京市海淀区****>*/private static String address(String address, int sensitiveSize) {if (oConvertUtils.isEmpty(address)) {return "";}int len = address.length();if(len<sensitiveSize){return address;}return formatRight(address, sensitiveSize);}/*** [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示* @param email 电子邮箱* @return <例子:g**@163>*/private static String email(String email) {if (oConvertUtils.isEmpty(email)) {return "";}int index = email.indexOf("@");if (index <= 1){return email;}String begin = email.substring(0, 1);String end = email.substring(index);String stars = "**";return begin + stars + end;}/*** [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号* @param cardNum 银行卡号* @return <例子:6222600**********1234>*/private static String bankCard(String cardNum) {if (oConvertUtils.isEmpty(cardNum)) {return "";}return formatBetween(cardNum, 6, 4);}/*** [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号* @param code 公司开户银行联号* @return <例子:12********>*/private static String cnapsCode(String code) {if (oConvertUtils.isEmpty(code)) {return "";}return formatRight(code, 2);}/*** 将右边的格式化成** @param str 字符串* @param reservedLength 保留长度* @return 格式化后的字符串*/private static String formatRight(String str, int reservedLength){String name = str.substring(0, reservedLength);String stars = String.join("", Collections.nCopies(str.length()-reservedLength, "*"));return name + stars;}/*** 将左边的格式化成** @param str 字符串* @param reservedLength 保留长度* @return 格式化后的字符串*/private static String formatLeft(String str, int reservedLength){int len = str.length();String show = str.substring(len-reservedLength);String stars = String.join("", Collections.nCopies(len-reservedLength, "*"));return stars + show;}/*** 将中间的格式化成** @param str 字符串* @param beginLen 开始保留长度* @param endLen 结尾保留长度* @return 格式化后的字符串*/private static String formatBetween(String str, int beginLen, int endLen){int len = str.length();String begin = str.substring(0, beginLen);String end = str.substring(len-endLen);String stars = String.join("", Collections.nCopies(len-beginLen-endLen, "*"));return begin + stars + end;}}

1-11:SymbolConstant

package com.example.poi.desensitization.utils;/*** @Description: 符号和特殊符号常用类* @Author xu* @create 2023/9/4 19*/
public class SymbolConstant {/*** 符号:点*/public static final String SPOT = ".";/*** 符号:双斜杠*/public static final String DOUBLE_BACKSLASH = "\\";/*** 符号:冒号*/public static final String COLON = ":";/*** 符号:逗号*/public static final String COMMA = ",";/*** 符号:左花括号 }*/public static final String LEFT_CURLY_BRACKET = "{";/*** 符号:右花括号 }*/public static final String RIGHT_CURLY_BRACKET = "}";/*** 符号:井号 #*/public static final String WELL_NUMBER = "#";/*** 符号:单斜杠*/public static final String SINGLE_SLASH = "/";/*** 符号:双斜杠*/public static final String DOUBLE_SLASH = "//";/*** 符号:感叹号*/public static final String EXCLAMATORY_MARK = "!";/*** 符号:下划线*/public static final String UNDERLINE = "_";/*** 符号:单引号*/public static final String SINGLE_QUOTATION_MARK = "'";/*** 符号:星号*/public static final String ASTERISK = "*";/*** 符号:百分号*/public static final String PERCENT_SIGN = "%";/*** 符号:美元 $*/public static final String DOLLAR = "$";/*** 符号:和 &*/public static final String AND = "&";/*** 符号:../*/public static final String SPOT_SINGLE_SLASH = "../";/*** 符号:..\\*/public static final String SPOT_DOUBLE_BACKSLASH = "..\\";/*** 系统变量前缀 #{*/public static final String SYS_VAR_PREFIX = "#{";/*** 符号 {{*/public static final String DOUBLE_LEFT_CURLY_BRACKET = "{{";/*** 符号:[*/public static final String SQUARE_BRACKETS_LEFT = "[";/*** 符号:]*/public static final String SQUARE_BRACKETS_RIGHT = "]";}

2:必须导入的POM的依赖

<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.6.RELEASE</version>
</dependency>
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version>
</dependency>
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.10</version>
</dependency>

3:使用操作

将SensitiveField放到对象的的属性上

将SensitiveEncode或SensitiveDecode放到方法的请求上,表示对方法返回的实体对象进行脱敏加密处理和是脱敏解密处理

注意对基本类型不能进行脱敏处理,不然需要改以上代码

更多推荐

数据脱敏sensitive(前端或数据库加密,解密)

本文发布于:2024-02-11 02:53:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1678732.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:数据库   数据   sensitive

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!