前言:
数据库字段在存储的时候进行加密或者解密的时候,在实体类字段上面添加上加密解密注解即可,需要用到几个工具类
使用展示
@EncryptTransaction
@DecryptTransaction
private String contactPersonPhone;
注解类1
package com.xinke.ebid.common.annotations;
import java.lang.annotation.*;
/**
* 解密注解
* @author CGY
*/
@Documented
@Inherited
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptTransaction {
}
注解类2
package com.xinke.ebid.common.annotations;
import java.lang.annotation.*;
/**
* 加密注解
* @author CGY
*/
@Documented
@Inherited
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptTransaction {
}
工具类
package com.xinke.ebid.common.shiro;
import com.xinke.ebid.common.annotations.EncryptTransaction;
import com.xinke.ebid.common.utils.AESUtil2;
import com.xinke.ebid.common.utils.AesUtil;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.Objects;
import java.util.Properties;
/**
* 用于处理请求数据字段加密
* @author CGY
*/
@Component
@Intercepts({ @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class), })
public class ParameterInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// @Signature 指定了 type= parameterHandler 后,这里的 invocation.getTarget()
// 便是parameterHandler
// 若指定ResultSetHandler ,这里则能强转为ResultSetHandler
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
// 获取参数对像,即 mapper 中 paramsType 的实例
Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
parameterField.setAccessible(true);
// 取出实例
Object parameterObject = parameterField.get(parameterHandler);
if (parameterObject != null) {
Class<?> parameterObjectClass = parameterObject.getClass();
// 取出当前当前类所有字段,传入加密方法
Field[] declaredFields = parameterObjectClass.getDeclaredFields();
encrypt(declaredFields, parameterObject);
}
return invocation.proceed();
}
public <T> T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException {
for (Field field : declaredFields) {
// 取出所有被EncryptTransaction注解的字段
EncryptTransaction encryptTransaction = field.getAnnotation(EncryptTransaction.class);
if (!Objects.isNull(encryptTransaction)) {
field.setAccessible(true);
Object object = field.get(paramsObject);
// 暂时只实现String类型的加密
if (object instanceof String) {
String value = (String) object;
// 加密
try {
field.set(paramsObject, AESUtil2.encrypt(value));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return paramsObject;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
package com.xinke.ebid.common.shiro;
import com.xinke.ebid.common.annotations.DecryptTransaction;
import com.xinke.ebid.common.utils.AESUtil2;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Properties;
/**
* 查询数据结果字段解密
* @author CGY
*/
@Component
@Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class }) })
public class ResultSetInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 取出查询的结果
Object resultObject = invocation.proceed();
if (Objects.isNull(resultObject)) {
return null;
}
// 基于selectList
if (resultObject instanceof ArrayList) {
ArrayList resultList = (ArrayList) resultObject;
if (!CollectionUtils.isEmpty(resultList)) {
for (Object result : resultList) {
// 逐一解密
this.decrypt(result);
}
}
// 基于selectOne
} else {
this.decrypt(resultObject);
}
return resultObject;
}
public <T> T decrypt(T result) throws IllegalAccessException {
// 取出resultType的类
Class<?> resultClass = result.getClass();
Field[] declaredFields = resultClass.getDeclaredFields();
for (Field field : declaredFields) {
// 取出所有被DecryptTransaction注解的字段
DecryptTransaction decryptTransaction = field.getAnnotation(DecryptTransaction.class);
if (!Objects.isNull(decryptTransaction)) {
field.setAccessible(true);
Object object = field.get(result);
// String的解密
if (object instanceof String) {
String value = (String) object;
// 对注解的字段进行逐一解密
try {
field.set(result, AESUtil2.decrypt(value));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
package com.xinke.ebid.common.utils;
import com.xinke.ebid.common.utils.ca.StringUtils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AESUtil2 {
private static final String defaultV = "6859505890402435";
private static final String key = "1061697007556132";
private static SecretKeySpec getKey(String strKey) throws Exception {
byte[] arrBTmp = strKey.getBytes();
byte[] arrB = new byte[16]; // 创建一个空的16位字节数组(默认值为0)
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB[i] = arrBTmp[i];
}
SecretKeySpec skeySpec = new SecretKeySpec(arrB, "AES");
return skeySpec;
}
/**
* 加密
*
* @param content
* @return
* @throws Exception
*/
public static String encrypt(String content) throws Exception {
if (StringUtils.isNotBlank(content)) {
final Base64.Encoder encoder = Base64.getEncoder();
SecretKeySpec skeySpec = getKey(key);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(defaultV.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(content.getBytes());
String encodedText = encoder.encodeToString(encrypted);
return encodedText;
}
return content;
}
/**
* 解密
*
* @param content
* @return
* @throws Exception
*/
public static String decrypt(String content) {
try {
final Base64.Decoder decoder = Base64.getDecoder();
SecretKeySpec skeySpec = getKey(key);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(defaultV.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] base64 = decoder.decode(content);
byte[] original = cipher.doFinal(base64);
String originalString = new String(original);
return originalString;
} catch (Exception e) {
return content;
}
}
}
使用mybatis-plus时,加密的工具类使用
package com.funong.matrix.core.annotation;
import com.funong.matrix.core.utils.AESUtil2;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.Objects;
import java.util.Properties;
import java.util.Map;
/**
* 用于处理请求数据字段加密
*
* @author CGY
*
*/
@Component
@Intercepts({ @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class), })
public class ParameterInterceptor implements Interceptor {
// 更新时的参数名称,ParamMap的key值
private static final String CRYPT = "et";
@Override
public Object intercept(Invocation invocation) throws Throwable {
// @Signature 指定了 type= parameterHandler 后,这里的 invocation.getTarget()
// 便是parameterHandler
// 若指定ResultSetHandler ,这里则能强转为ResultSetHandler
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
// 获取参数对像,即 mapper 中 paramsType 的实例
Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
parameterField.setAccessible(true);
// 取出实例
Object parameterObject = parameterField.get(parameterHandler);
if (parameterObject != null) {
Object sensitiveObject = null;
if (parameterObject instanceof MapperMethod.ParamMap) {
// 更新操作被拦截
Map paramMap = (Map) parameterObject;
if (paramMap.containsKey(CRYPT)) {
sensitiveObject = paramMap.get(CRYPT);
}
// 插入操作被拦截,parameterObject即为待插入的实体对象
} else {
// 插入操作被拦截,parameterObject即为待插入的实体对象
sensitiveObject = parameterObject;
}
// 获取不到数据就直接放行
if (Objects.isNull(sensitiveObject)) {
return invocation.proceed();
}
// 校验该实例的类是否被@EncryptTransaction所注解
Class<?> sensitiveObjectClass = sensitiveObject.getClass();
Field[] declaredFields = sensitiveObjectClass.getDeclaredFields();
encrypt(declaredFields, sensitiveObject);
}
return invocation.proceed();
}
public <T> T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException {
for (Field field : declaredFields) {
// 取出所有被EncryptTransaction注解的字段
EncryptTransaction encryptTransaction = field.getAnnotation(EncryptTransaction.class);
if (!Objects.isNull(encryptTransaction)) {
field.setAccessible(true);
Object object = field.get(paramsObject);
// 暂时只实现String类型的加密
if (object instanceof String) {
String value = (String) object;
// 加密
try {
field.set(paramsObject, AESUtil2.encrypt(value));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return paramsObject;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}