|
|
@ -1,9 +1,7 @@
|
|
|
|
package cokr.xit.base.crypto;
|
|
|
|
package cokr.xit.base.crypto;
|
|
|
|
|
|
|
|
|
|
|
|
import java.sql.PreparedStatement;
|
|
|
|
|
|
|
|
import java.sql.SQLException;
|
|
|
|
import java.sql.SQLException;
|
|
|
|
import java.sql.Statement;
|
|
|
|
import java.sql.Statement;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.function.BiFunction;
|
|
|
|
import java.util.function.BiFunction;
|
|
|
@ -11,10 +9,13 @@ import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.beanutils.BeanUtils;
|
|
|
|
import org.apache.commons.beanutils.BeanUtils;
|
|
|
|
import org.apache.commons.beanutils.PropertyUtils;
|
|
|
|
import org.apache.commons.beanutils.PropertyUtils;
|
|
|
|
import org.apache.ibatis.executor.parameter.ParameterHandler;
|
|
|
|
import org.apache.ibatis.executor.Executor;
|
|
|
|
import org.apache.ibatis.executor.resultset.ResultSetHandler;
|
|
|
|
import org.apache.ibatis.executor.resultset.ResultSetHandler;
|
|
|
|
|
|
|
|
import org.apache.ibatis.mapping.MappedStatement;
|
|
|
|
import org.apache.ibatis.plugin.Intercepts;
|
|
|
|
import org.apache.ibatis.plugin.Intercepts;
|
|
|
|
import org.apache.ibatis.plugin.Signature;
|
|
|
|
import org.apache.ibatis.plugin.Signature;
|
|
|
|
|
|
|
|
import org.apache.ibatis.session.ResultHandler;
|
|
|
|
|
|
|
|
import org.apache.ibatis.session.RowBounds;
|
|
|
|
|
|
|
|
|
|
|
|
import cokr.xit.base.crypto.Cryptography.Config;
|
|
|
|
import cokr.xit.base.crypto.Cryptography.Config;
|
|
|
|
import cokr.xit.foundation.data.paging.MybatisPlugin;
|
|
|
|
import cokr.xit.foundation.data.paging.MybatisPlugin;
|
|
|
@ -23,31 +24,12 @@ import cokr.xit.foundation.data.paging.MybatisPlugin;
|
|
|
|
* @author mjkhan
|
|
|
|
* @author mjkhan
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@Intercepts({
|
|
|
|
@Intercepts({
|
|
|
|
@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),
|
|
|
|
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
|
|
|
|
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
|
|
|
|
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
public class CryptographySupport extends MybatisPlugin {
|
|
|
|
public class CryptographySupport extends MybatisPlugin {
|
|
|
|
private static final ThreadLocal<List<Object>> cached = new ThreadLocal<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static boolean isCached(Object obj) {
|
|
|
|
|
|
|
|
List<Object> objs = cached.get();
|
|
|
|
|
|
|
|
return objs != null ? objs.contains(obj) : false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static void setCache(Object obj) {
|
|
|
|
|
|
|
|
List<Object> objs = cached.get();
|
|
|
|
|
|
|
|
if (objs == null)
|
|
|
|
|
|
|
|
cached.set(objs = new ArrayList<>());
|
|
|
|
|
|
|
|
objs.add(obj);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void clear() {
|
|
|
|
|
|
|
|
List<Object> objs = cached.get();
|
|
|
|
|
|
|
|
if (objs != null)
|
|
|
|
|
|
|
|
objs.clear();
|
|
|
|
|
|
|
|
cached.remove();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Map<String, Cryptography> cryptos;
|
|
|
|
private Map<String, Cryptography> cryptos;
|
|
|
|
|
|
|
|
|
|
|
|
public CryptographySupport() {
|
|
|
|
public CryptographySupport() {
|
|
|
@ -62,10 +44,8 @@ public class CryptographySupport extends MybatisPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
protected Object setParameters(ParameterHandler parameterHandler, PreparedStatement statement) throws SQLException {
|
|
|
|
protected Object query(Executor executor, MappedStatement mappedStatement, Object obj, RowBounds rowBounds, ResultHandler<?> resultHandler) throws SQLException {
|
|
|
|
Object obj = parameterHandler.getParameterObject();
|
|
|
|
return encrypt(obj, () -> super.query(executor, mappedStatement, obj, rowBounds, resultHandler));
|
|
|
|
encrypt(obj);
|
|
|
|
|
|
|
|
return super.setParameters(parameterHandler, statement);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@ -82,24 +62,43 @@ public class CryptographySupport extends MybatisPlugin {
|
|
|
|
return obj;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected Object update(Executor executor, MappedStatement mappedStatement, Object obj) throws SQLException {
|
|
|
|
|
|
|
|
return encrypt(obj, () -> super.update(executor, mappedStatement, obj));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean isEnabled(Object obj) {
|
|
|
|
private boolean isEnabled(Object obj) {
|
|
|
|
return !isEmpty(obj)
|
|
|
|
return !isEmpty(obj)
|
|
|
|
&& !isEmpty(cryptos);
|
|
|
|
&& !isEmpty(cryptos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void encrypt(Object obj) {
|
|
|
|
private static interface ResultSupplier {
|
|
|
|
if (!isEnabled(obj)) return;
|
|
|
|
Object get() throws Exception;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Object encrypt(Object obj, ResultSupplier resultSupplier) {
|
|
|
|
|
|
|
|
boolean enabled = isEnabled(obj);
|
|
|
|
|
|
|
|
if (enabled)
|
|
|
|
|
|
|
|
process(obj, (arg) -> convert(arg, (crypto, val) -> crypto.encrypt(val)));
|
|
|
|
|
|
|
|
|
|
|
|
process(obj, (arg) -> convert(arg, (crypto, val) -> crypto.encrypt(val), true));
|
|
|
|
Object result = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
result = resultSupplier.get();
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
throw runtimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void convert(Object obj, BiFunction<Cryptography, Object, Object> converter, boolean cache) {
|
|
|
|
if (enabled)
|
|
|
|
|
|
|
|
process(obj, (arg) -> convert(arg, (crypto, val) -> crypto.decrypt(val)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void convert(Object obj, BiFunction<Cryptography, Object, Object> converter) {
|
|
|
|
List<Cryptography.TargetValue> targetValues = Cryptography.Config.get().getTargetValues(obj);
|
|
|
|
List<Cryptography.TargetValue> targetValues = Cryptography.Config.get().getTargetValues(obj);
|
|
|
|
if (targetValues.isEmpty()) return;
|
|
|
|
if (targetValues.isEmpty()) return;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
if (cache && isCached(obj)) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Cryptography.TargetValue target: targetValues) {
|
|
|
|
for (Cryptography.TargetValue target: targetValues) {
|
|
|
|
for (String cryptoDef: target.getCryptoDefs()) {
|
|
|
|
for (String cryptoDef: target.getCryptoDefs()) {
|
|
|
|
Cryptography crypto = cryptos.get(cryptoDef);
|
|
|
|
Cryptography crypto = cryptos.get(cryptoDef);
|
|
|
@ -127,9 +126,6 @@ public class CryptographySupport extends MybatisPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (cache)
|
|
|
|
|
|
|
|
setCache(obj);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw runtimeException(e);
|
|
|
|
throw runtimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -138,6 +134,6 @@ public class CryptographySupport extends MybatisPlugin {
|
|
|
|
private void decrypt(Object obj) {
|
|
|
|
private void decrypt(Object obj) {
|
|
|
|
if (!isEnabled(obj)) return;
|
|
|
|
if (!isEnabled(obj)) return;
|
|
|
|
|
|
|
|
|
|
|
|
convert(obj, (crypto, val) -> crypto.decrypt(val), false);
|
|
|
|
convert(obj, (crypto, val) -> crypto.decrypt(val));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|