MyBatisPlus数据自动加解密存取和字段防篡改有效性校验码自动生成存储处理器

整体原理:用Mybatis拦截器拦截ResultSetHandler,做属性解密和完整性校奏。替换默认的ParameterHandler处理器。做属性加密存储和完整性加密存储。
代码结构如下:
MyBatisPlus数据自动加解密存取和字段防篡改有效性校验码自动生成存储处理器_第1张图片
各功能类解释:
1、EntityClassResolver:用于解析当前MapperStatament的Entity参数。
2、EntityValueHelper: 获取或设置Entity对象的属性值工具。
3、SecretConfigurationCustomizer:使得SecretMybatisXMLLanguageDriver生效的自定义配置。替换mybatisPlus默认的XMLLanguageDriver
4、SecretMybatisXMLLanguageDriver:使得SecretMybatisParameterHandler生效的自定义配置。替换mybatisPlus默认的MybatisParameterHandler
5、SecretDecryptInterceptor,拦截ResultSetHandler.handleResultSets,解密带SecretField字段的entity属性。
6、SecretField,标记需要加解密和完整性校验的字段注解。
7、SecretModel,标记该实体有需要加解密的字段。
8、SecretProvider,加解密码供应商。
9、SecretProviders,加解密供应商工具类。
10、SeretSecurityAutoConfiguration,总配置类,用于开启是否向Spring注册启用加密码组件。
SecretWrapper,加解密过程相关临时变量封装类。
SecretWrarpperEnhancer:低层次代码向高层次代码的entity对象设置一些加解密字段的扩展接口。
SecretWrapperEnhancers,扩展接口工具类。

几个关键类:

public class SecretConfigurationCustomizer implements ConfigurationCustomizer {

    @Override
    public void customize(Configuration configuration) {
        LanguageDriverRegistry languageRegistry = configuration.getLanguageRegistry();
        languageRegistry.setDefaultDriverClass(SecretMybatisXMLLanguageDriver.class);
    }
}
public class SecretMybatisXMLLanguageDriver extends XMLLanguageDriver {

    @Override
    public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject,
                                                   BoundSql boundSql) {
        /* 使用自定义 ParameterHandler */
        return new SecretMybatisParameterHandler(mappedStatement, parameterObject, boundSql);
    }
}

@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class)
})
public class SecretDecryptInterceptor implements Interceptor {

    private final static Map<String, Boolean> EXISTS_DECRYPT = new HashMap<>();
    private final static Map<String, SecretWrapper> NEED_DECRYPT_FIELDS = new HashMap<>();

    @Autowired
    private SecretProvider secretProvider;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取结果集的类型
        MappedStatement mappedStatement = resolveMappedStatement(invocation);
        String id = mappedStatement.getId();
        //
        Boolean needDecrypt = EXISTS_DECRYPT.get(id);
        if (null != needDecrypt && !needDecrypt) {
            return invocation.proceed();
        }
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        if (ZYListUtils.isEmptyList(resultMaps)) {
            EXISTS_DECRYPT.put(id, false);
            return invocation.proceed();
        }
        SecretWrapper secretWrapper = NEED_DECRYPT_FIELDS.get(id);
        if (null == secretWrapper) {
            Class<?> resultType = resultMaps.get(0).getType();
            secretWrapper = new SecretWrapper(resultType);
            if (secretWrapper.isEmpty()) {
                EXISTS_DECRYPT.put(id, false);
                return invocation.proceed();
            } else {
                EXISTS_DECRYPT.put(id, true);
                NEED_DECRYPT_FIELDS.put(id, secretWrapper);
            }
        }

        Object resultObject = invocation.proceed();
        if (null != resultObject && resultObject instanceof List) {
            List<?> list = (List<?>) resultObject;
            for (Object item : list) {
                this.doDecryptObjectValue(item, secretWrapper);
            }
        }
        return resultObject;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

    private MappedStatement resolveMappedStatement(Invocation invocation) {
        DefaultResultSetHandler defaultResultSetHandler = (DefaultResultSetHandler) invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(defaultResultSetHandler);
        return (MappedStatement) metaObject.getValue("mappedStatement");
    }

    protected void doDecryptObjectValue(Object data, SecretWrapper secretWrapper) {
        // 解密
        List<String> decryptFields = secretWrapper.getDecryptFields();
        for (String field : decryptFields) {
            Object fieldValue = ZYBeanUtils.getProperty(data, field);
            if (ZYStrUtils.isNotNull(fieldValue)) {
                fieldValue = SecretProviders.decrypt(String.valueOf(fieldValue));
                ZYBeanUtils.setProperty(data, field, fieldValue);
            }
        }

        // 完整性校验
        List<String> signFields = secretWrapper.getSignFields();
        Map<String, String> signCodeFieldContainer = secretWrapper.getSignCodeFieldContainer();
        for (String signField : signFields) {
            Object fieldValue = ZYBeanUtils.getProperty(data, signField);
            if (ZYStrUtils.isNotNull(fieldValue)) {
                // 找到当前属性的签名
                String signCodeField = signCodeFieldContainer.get(signField);
                Object signCodeValue = ZYBeanUtils.getProperty(data, signCodeField);
                if (ZYStrUtils.isNotNull(signCodeValue)) {
                    // 校验数据完整性
                    boolean legal = SecretProviders.isLegal(String.valueOf(fieldValue), String.valueOf(signCodeValue));
                    if (!legal) {
                        throw new LocalException("非法数据" + fieldValue);
                    }
                }
            }
        }
    }
}
public class SecretMybatisParameterHandler extends DefaultParameterHandler {

    private final TypeHandlerRegistry typeHandlerRegistry;
    private final MappedStatement mappedStatement;
    private final Object parameterObject;
    private final BoundSql boundSql;
    private final Configuration configuration;

    public SecretMybatisParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        super(mappedStatement, processBatch(mappedStatement, parameterObject), boundSql);
        this.mappedStatement = mappedStatement;
        this.configuration = mappedStatement.getConfiguration();
        this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
        this.parameterObject = parameterObject;
        this.boundSql = boundSql;
    }

    /**
     * 批量(填充主键 ID)
     *
     * @param ms              MappedStatement
     * @param parameterObject 插入数据库对象
     * @return ignore
     */
    protected static Object processBatch(MappedStatement ms, Object parameterObject) {
        //检查 parameterObject
        if (null == parameterObject) {
            return null;
        }
        // 全局配置是否配置填充器
        MetaObjectHandler metaObjectHandler = GlobalConfigUtils.getMetaObjectHandler(ms.getConfiguration());
        boolean isFill = false;
        boolean isInsert = false;
        /* 只处理插入或更新操作 */
        if (ms.getSqlCommandType() == SqlCommandType.INSERT) {
            isFill = true;
            isInsert = true;
        } else if (ms.getSqlCommandType() == SqlCommandType.UPDATE &&
                metaObjectHandler != null && metaObjectHandler.openUpdateFill()) {
            isFill = true;
        }
        if (isFill) {
            Collection<Object> parameters = getParameters(parameterObject);
            if (null != parameters) {
                List<Object> objList = new ArrayList<>();
                for (Object parameter : parameters) {
                    TableInfo tableInfo = TableInfoHelper.getTableInfo(parameter.getClass());
                    if (null != tableInfo) {
                        objList.add(populateKeys(metaObjectHandler, tableInfo, ms, parameter, isInsert));
                    } else {
                        /*
                         * 非表映射类不处理
                         */
                        objList.add(parameter);
                    }
                }
                return objList;
            } else {
                TableInfo tableInfo = null;
                if (parameterObject instanceof Map) {
                    Map map = (Map) parameterObject;
                    if (map.containsKey(Constants.ENTITY)) {
                        Object et = map.get(Constants.ENTITY);
                        if (et != null) {
                            if (et instanceof Map) {
                                Map realEtMap = (Map) et;
                                if (realEtMap.containsKey("MP_OPTLOCK_ET_ORIGINAL")) {
                                    //refer to OptimisticLockerInterceptor.MP_OPTLOCK_ET_ORIGINAL
                                    tableInfo = TableInfoHelper.getTableInfo(realEtMap.get("MP_OPTLOCK_ET_ORIGINAL").getClass());
                                }
                            } else {
                                tableInfo = TableInfoHelper.getTableInfo(et.getClass());
                            }
                        }
                    }
                } else {
                    tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());
                }
                return populateKeys(metaObjectHandler, tableInfo, ms, parameterObject, isInsert);
            }
        }
        return parameterObject;
    }

    /**
     * 处理正常批量插入逻辑
     * 

* org.apache.ibatis.session.defaults.DefaultSqlSession$StrictMap 该类方法 * wrapCollection 实现 StrictMap 封装逻辑 *

* * @param parameter 插入数据库对象 * @return */
@SuppressWarnings({"rawtypes", "unchecked"}) protected static Collection<Object> getParameters(Object parameter) { Collection<Object> parameters = null; if (parameter instanceof Collection) { parameters = (Collection) parameter; } else if (parameter instanceof Map) { Map parameterMap = (Map) parameter; if (parameterMap.containsKey("collection")) { parameters = (Collection) parameterMap.get("collection"); } else if (parameterMap.containsKey("list")) { parameters = (List) parameterMap.get("list"); } else if (parameterMap.containsKey("array")) { parameters = Arrays.asList((Object[]) parameterMap.get("array")); } } return parameters; } /** * 自定义元对象填充控制器 * * @param metaObjectHandler 元数据填充处理器 * @param tableInfo 数据库表反射信息 * @param ms MappedStatement * @param parameterObject 插入数据库对象 * @return Object */ protected static Object populateKeys(MetaObjectHandler metaObjectHandler, TableInfo tableInfo, MappedStatement ms, Object parameterObject, boolean isInsert) { if (null == tableInfo) { /* 不处理 */ return parameterObject; } /* 自定义元对象填充控制器 */ MetaObject metaObject = ms.getConfiguration().newMetaObject(parameterObject); // 填充主键 if (isInsert && !StringUtils.isEmpty(tableInfo.getKeyProperty()) && null != tableInfo.getIdType() && tableInfo.getIdType().getKey() >= 3) { Object idValue = metaObject.getValue(tableInfo.getKeyProperty()); /* 自定义 ID */ if (StringUtils.checkValNull(idValue)) { if (tableInfo.getIdType() == IdType.ID_WORKER) { metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.getId()); } else if (tableInfo.getIdType() == IdType.ID_WORKER_STR) { metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.getIdStr()); } else if (tableInfo.getIdType() == IdType.UUID) { metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.get32UUID()); } } } doCompleteSignCode(metaObject, tableInfo); if (metaObjectHandler != null) { if (isInsert && metaObjectHandler.openInsertFill()) { // 插入填充 metaObjectHandler.insertFill(metaObject); } else if (!isInsert) { // 更新填充 metaObjectHandler.updateFill(metaObject); } } return metaObject.getOriginalObject(); } // 可提前设置完整性signCode的值,所放提前设置 private static void doCompleteSignCode(MetaObject metaObject, TableInfo tableInfo) { Class<?> clazz = tableInfo.getClazz(); SecretWrapper secretWrapper = new SecretWrapper(clazz); if (secretWrapper.isEmpty()) { return; } Map<String, String> signContentContainer = secretWrapper.getSignContentContainer(); signContentContainer.forEach((signCodeField, signContentField) -> { setSignCodeValue(metaObject, signCodeField, signContentField); }); } private static void setSignCodeValue(MetaObject metaObject, String signCodeField, String signContentField) { if (ZYStrUtils.isNull(signContentField)) { return; } Object signContent = EntityValueHelper.getProperties(metaObject, signContentField); if (ZYStrUtils.isNull(signContent)) { return; } // 用完整性数据字段内容加密 String signCode = SecretProviders.genLegalSign(String.valueOf(signContent)); if (ZYStrUtils.isNotNull(signCode)) { EntityValueHelper.setProperties(metaObject, signCodeField, signCode); } } @Override @SuppressWarnings("unchecked") public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (ZYListUtils.isEmptyList(parameterMappings)) { return; } for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() == ParameterMode.OUT) { continue; } Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); // 不能破坏对象原来的值,所以放这处理最终的设置sql数据 value = doEncryptIfNecessary(metaObject, propertyName, value); } TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException | SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } // 解密对象 private Object doEncryptIfNecessary(MetaObject metaObject, String propertyName, Object value) { if (!isNecessarySecret(metaObject, value)) { return value; } Class<?> moduleClass = EntityClassResolver.resolveClass(mappedStatement, parameterObject); if (null == moduleClass) { return value; } SecretWrapper secretWrapper = new SecretWrapper(moduleClass); if (secretWrapper.isEmpty()) { return value; } PropertyTokenizer propertyTokenizer = new PropertyTokenizer(propertyName); // 加个密 SecretModel secretField = secretWrapper.getSecretField(propertyTokenizer); if (null != secretField && secretField.isNeedEncrypt()) { return SecretProviders.encrypt(String.valueOf(value)); } return value; } private boolean isNecessarySecret(MetaObject metaObject, Object value) { SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); // 不是添加或修改 if (!sqlCommandType.equals(SqlCommandType.INSERT) && !sqlCommandType.equals(SqlCommandType.UPDATE)) { return false; } if (ZYStrUtils.isNull(value)) { return false; } // 只支持处理string类型 return value instanceof String; } }

你可能感兴趣的:(mybatis,java)