tableList;
@@ -112,24 +117,38 @@ public class CCJSQLStatementContext {
PlainSelect plain = (PlainSelect) select.getSelectBody();
Expression where = plain.getWhere();
- where.accept(new ExpressionDeParser(null, b) {
- @Override
- public void visit(EqualsTo equalsTo) {
- Column leftExpression = (Column) equalsTo.getLeftExpression();
-
- Expression rightExpression = equalsTo.getRightExpression();
-
- if (rightExpression instanceof JdbcParameter){
- JdbcParameter jdbcParameter = (JdbcParameter) rightExpression;
- Integer index = jdbcParameter.getIndex();
- CCJSQLCryptExpressionDTO dto = new CCJSQLCryptExpressionDTO();
- dto.setAlias(TablesNamesFinderPlus.getAlias(leftExpression.getTable()));
- dto.setColumnName(leftExpression.getColumnName());
- dto.setIndex(index);
- list.add(dto);
+ if (null != where) {
+ where.accept(new ExpressionDeParser(null, b) {
+ @Override
+ public void visit(EqualsTo equalsTo) {
+ Expression leftExp = equalsTo.getLeftExpression();
+ // 判断 1 = 1 情况
+ boolean isLongValue = leftExp instanceof LongValue;
+ Column leftExpression = null;
+ if (!isLongValue) {
+ leftExpression = (Column) leftExp;
+ }
+
+ Expression rightExpression = equalsTo.getRightExpression();
+ if (null != leftExpression && rightExpression instanceof JdbcParameter) {
+ JdbcParameter jdbcParameter = (JdbcParameter) rightExpression;
+ Integer index = jdbcParameter.getIndex();
+ CCJSQLCryptExpressionDTO dto = new CCJSQLCryptExpressionDTO();
+ String alias = TablesNamesFinderPlus.getAlias(leftExpression.getTable());
+ if (StrUtil.isBlank(alias)) {
+ log.error("---> [Mybatis 加密拦截器] 字段 {} 未设置归属表别名,默认使用 t 做为字段归属表的别名...",
+ leftExpression.getColumnName());
+ dto.setAlias("t");
+ } else {
+ dto.setAlias(alias);
+ }
+ dto.setColumnName(leftExpression.getColumnName());
+ dto.setIndex(index);
+ list.add(dto);
+ }
}
- }
- });
+ });
+ }
return list;
}
diff --git a/src/main/java/org/dflish/mybatis/encrypt/plugins/DecryptInterceptor.java b/src/main/java/org/dflish/mybatis/encrypt/plugins/DecryptInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..b79f92937083fe84232713bd215f2ddd0c903d92
--- /dev/null
+++ b/src/main/java/org/dflish/mybatis/encrypt/plugins/DecryptInterceptor.java
@@ -0,0 +1,103 @@
+package org.dflish.mybatis.encrypt.plugins;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
+import org.apache.ibatis.executor.resultset.ResultSetHandler;
+import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.SystemMetaObject;
+import org.dflish.mybatis.encrypt.annotation.SensitiveData;
+import org.dflish.mybatis.encrypt.properties.EnCryptProperties;
+import org.dflish.mybatis.encrypt.util.DecryptUtil;
+
+import java.lang.reflect.Proxy;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * 解密拦截器
+ *
+ * @author song_jx
+ * @date 2021-09-04 03:28:50
+ */
+@Intercepts({
+ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
+})
+public class DecryptInterceptor implements Interceptor {
+
+ private static final Log log = LogFactory.get();
+
+ private final EnCryptProperties properties;
+
+ public DecryptInterceptor(EnCryptProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ // 取出查询的结果
+ Object resultObject = invocation.proceed();
+
+ if (ObjectUtil.isNull(resultObject)) {
+ return null;
+ }
+
+ if (resultObject instanceof ArrayList) {
+ // 基于selectList
+ List resultList = (ArrayList) resultObject;
+ if (CollUtil.isNotEmpty(resultList) && isNeedDecrypt(resultList.get(0))) {
+ for (Object result : resultList) {
+ //逐一解密
+ DecryptUtil.decrypt(result, properties.getKey());
+ }
+ }
+ } else {
+ // 基于selectOne
+ if (isNeedDecrypt(resultObject)) {
+ DecryptUtil.decrypt(resultObject, properties.getKey());
+ }
+ }
+
+ return resultObject;
+ }
+
+ @Override
+ public Object plugin(Object target) {
+ return Plugin.wrap(target, this);
+ }
+
+ @Override
+ public void setProperties(Properties properties) {
+
+ }
+
+ /**
+ *
+ * 获得真正的处理对象,可能多层代理.
+ *
+ */
+ private Object realTarget(Object target) {
+ if (Proxy.isProxyClass(target.getClass())) {
+ MetaObject metaObject = SystemMetaObject.forObject(target);
+ return realTarget(metaObject.getValue("h.target"));
+ }
+ return target;
+ }
+
+ /**
+ * 是否需要解密
+ *
+ * @param object 对象
+ * @return @return boolean
+ * @author song_jx
+ */
+ private boolean isNeedDecrypt(Object object) {
+ return AnnotationUtil.hasAnnotation(object.getClass(), SensitiveData.class);
+ }
+
+}
diff --git a/src/main/java/org/dflish/mybatis/encrypt/plugins/EnCryptInterceptor.java b/src/main/java/org/dflish/mybatis/encrypt/plugins/EncryptInterceptor.java
similarity index 59%
rename from src/main/java/org/dflish/mybatis/encrypt/plugins/EnCryptInterceptor.java
rename to src/main/java/org/dflish/mybatis/encrypt/plugins/EncryptInterceptor.java
index cf55ce64c0813f57604af762ae1b3e627699adf2..18b68821610f58fc18cccccad2410ab7bbee33fc 100644
--- a/src/main/java/org/dflish/mybatis/encrypt/plugins/EnCryptInterceptor.java
+++ b/src/main/java/org/dflish/mybatis/encrypt/plugins/EncryptInterceptor.java
@@ -1,41 +1,43 @@
package org.dflish.mybatis.encrypt.plugins;
-import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
-import lombok.extern.slf4j.Slf4j;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
-import org.apache.ibatis.plugin.Interceptor;
-import org.apache.ibatis.plugin.Intercepts;
-import org.apache.ibatis.plugin.Invocation;
-import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.dflish.mybatis.encrypt.properties.EnCryptProperties;
import org.dflish.mybatis.encrypt.rewrite.EncryptPreParameterRewriter;
+import java.lang.reflect.Proxy;
import java.sql.Statement;
import java.util.List;
+import java.util.Properties;
/**
+ * 加密拦截器
+ *
* @author liangwx
+ * @date 2021-09-04 03:28:58
*/
-@Slf4j
@Intercepts({
@Signature(type = StatementHandler.class, method = "parameterize", args = Statement.class)
})
-public class EnCryptInterceptor implements Interceptor {
+public class EncryptInterceptor implements Interceptor {
+
+ private static final Log log = LogFactory.get();
private final EncryptPreParameterRewriter rewriter;
- public EnCryptInterceptor(EnCryptProperties properties) {
+ public EncryptInterceptor(EnCryptProperties properties) {
this.rewriter = new EncryptPreParameterRewriter(properties);
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
-
- Object target = PluginUtils.realTarget(invocation.getTarget());
+ Object target = realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(target);
MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
@@ -49,4 +51,28 @@ public class EnCryptInterceptor implements Interceptor {
return returnObj;
}
+
+ @Override
+ public Object plugin(Object target) {
+ return Plugin.wrap(target, this);
+ }
+
+ @Override
+ public void setProperties(Properties properties) {
+
+ }
+
+ /**
+ *
+ * 获得真正的处理对象,可能多层代理.
+ *
+ */
+ private Object realTarget(Object target) {
+ if (Proxy.isProxyClass(target.getClass())) {
+ MetaObject metaObject = SystemMetaObject.forObject(target);
+ return realTarget(metaObject.getValue("h.target"));
+ }
+ return target;
+ }
+
}
diff --git a/src/main/java/org/dflish/mybatis/encrypt/rule/EncryptRule.java b/src/main/java/org/dflish/mybatis/encrypt/rule/EncryptRule.java
index cee0031d197400507f4732cf03fbe2b4a939c3e0..9d404d387ee3b177b6c622b2bc5c499ee4b8a98b 100644
--- a/src/main/java/org/dflish/mybatis/encrypt/rule/EncryptRule.java
+++ b/src/main/java/org/dflish/mybatis/encrypt/rule/EncryptRule.java
@@ -1,15 +1,12 @@
package org.dflish.mybatis.encrypt.rule;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.symmetric.AES;
-import org.apache.commons.codec.digest.DigestUtils;
import org.dflish.mybatis.encrypt.properties.EnCryptProperties;
import org.dflish.mybatis.encrypt.properties.EncryptColumnRuleConfiguration;
import org.dflish.mybatis.encrypt.properties.EncryptTableRuleConfiguration;
+import org.dflish.mybatis.encrypt.util.AesUtils;
import org.dflish.mybatis.encrypt.util.DesensitizedExecutor;
import org.dflish.mybatis.encrypt.util.DesensitizedType;
-import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
@@ -24,16 +21,10 @@ public class EncryptRule {
private final String key;
- private final AES aes;
-
-
public EncryptRule(EnCryptProperties properties) {
this.properties = properties;
this.tables = properties.getTables();
this.key = properties.getKey();
-
- final byte[] bytes = Arrays.copyOf(DigestUtils.sha1(key), 16);
- aes = SecureUtil.aes(bytes);
}
public Optional getEncryptColumnRuleConfiguration(String tableName, String columnName){
@@ -73,7 +64,7 @@ public class EncryptRule {
final EncryptColumnRuleConfiguration configuration = encryptColumnRuleConfiguration.get();
if (configuration.getEncryptor()){
- return aes.encryptBase64((String) originalValues);
+ return AesUtils.encrypt((String) originalValues, key);
}
if (configuration.getDesensitized()){
diff --git a/src/main/java/org/dflish/mybatis/encrypt/util/AesUtils.java b/src/main/java/org/dflish/mybatis/encrypt/util/AesUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..2d43c5cd0565eb06c4c99839e7eefea124e95ea9
--- /dev/null
+++ b/src/main/java/org/dflish/mybatis/encrypt/util/AesUtils.java
@@ -0,0 +1,90 @@
+package org.dflish.mybatis.encrypt.util;
+
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
+import org.apache.commons.codec.binary.Hex;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * aes工具类
+ *
+ * @author song_jx
+ * @date 2021-09-04 05:14:04
+ */
+public class AesUtils {
+
+ private static final Log log = LogFactory.get();
+
+ /**
+ * 算法
+ */
+ private static final String ALGORITHM = "AES";
+
+ /**
+ * 生成mysql的aes密钥
+ *
+ * @param key 密钥
+ * @param encoding 编码
+ * @return @return {@link SecretKeySpec }
+ * @author song_jx
+ */
+ public static SecretKeySpec generateMySQLAESKey(final String key, final String encoding) throws Exception {
+ final byte[] finalKey = new byte[16];
+ int i = 0;
+ for (byte b : key.getBytes(encoding)) {
+ finalKey[i++ % 16] ^= b;
+ }
+ return new SecretKeySpec(finalKey, ALGORITHM);
+ }
+
+ /**
+ * 解密
+ *
+ * @param data 数据
+ * @param key 密钥
+ * @return @return {@link String }
+ * @throws Exception 异常
+ * @author song_jx
+ */
+ public static String decrypt(String data, String key) {
+ String decryptStr = StrUtil.EMPTY;
+ try {
+ final Cipher decryptCipher = Cipher.getInstance(ALGORITHM);
+ decryptCipher.init(Cipher.DECRYPT_MODE, generateMySQLAESKey(key, CharsetUtil.UTF_8));
+ decryptStr = new String(decryptCipher.doFinal(Hex.decodeHex(data.toCharArray())));
+ } catch (Exception e) {
+ log.error("--- [AES工具类] aes解密失败...", e);
+ }
+ return decryptStr;
+ }
+
+ /**
+ * 加密
+ *
+ * @param data 数据
+ * @param key 密钥
+ * @return @return {@link String }
+ * @author song_jx
+ */
+ public static String encrypt(String data, String key) {
+ String encryptStr = StrUtil.EMPTY;
+ try {
+ final Cipher encryptCipher = Cipher.getInstance(ALGORITHM);
+ encryptCipher.init(Cipher.ENCRYPT_MODE, generateMySQLAESKey(key, CharsetUtil.UTF_8));
+ char[] code = Hex.encodeHex(encryptCipher.doFinal(data.getBytes(CharsetUtil.UTF_8)));
+ StringBuilder builder = new StringBuilder();
+ for (char d : code) {
+ builder.append(d);
+ }
+ encryptStr = builder.toString();
+ } catch (Exception e) {
+ log.error("--- [AES工具类] aes加密失败...", e);
+ }
+ return encryptStr;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/dflish/mybatis/encrypt/util/DecryptUtil.java b/src/main/java/org/dflish/mybatis/encrypt/util/DecryptUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b2afd76601509ed43b373a260f41c42b0f106e6
--- /dev/null
+++ b/src/main/java/org/dflish/mybatis/encrypt/util/DecryptUtil.java
@@ -0,0 +1,59 @@
+package org.dflish.mybatis.encrypt.util;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ReflectUtil;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
+import org.dflish.mybatis.encrypt.annotation.DecryptTransaction;
+
+import java.lang.reflect.Field;
+
+/**
+ * 解密工具类
+ *
+ * @author song_jx
+ * @date 2021-09-04 04:13:13
+ */
+public class DecryptUtil {
+
+ private static final Log log = LogFactory.get();
+
+ /**
+ * 解密
+ *
+ * @param result 结果
+ * @param key 关键
+ * @return @return {@link T }
+ * @author song_jx
+ */
+ public static T decrypt(T result, String key) {
+ try {
+ // 取出resultType的类
+ Field[] declaredFields = ReflectUtil.getFields(result.getClass());
+ for (Field field : declaredFields) {
+ // 取出所有被DecryptTransaction注解的字段
+ DecryptTransaction annotation = AnnotationUtil.getAnnotation(field, DecryptTransaction.class);
+ if (ObjectUtil.isNotNull(annotation)) {
+ Object fieldValue = ReflectUtil.getFieldValue(result, field);
+ // String的解密
+ if (fieldValue instanceof String) {
+ String value = (String) fieldValue;
+ value = AesUtils.decrypt(value, key);
+
+ // 数据脱敏
+ if (annotation.isDesensitized()) {
+ value = DesensitizedExecutor.desensitized(annotation.desensitizedType(), value);
+ }
+
+ field.set(result, value);
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.error("---> [Mybatis 解密拦截器] 字段注解 解密异常...", e);
+ }
+ return result;
+ }
+
+}