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

整体原理:用Mybatis拦截器拦截ResultSetHandler,做属性解密和完整性校奏。替换默认的ParameterHandler处理器。做属性加密存储和完整性加密存储。
代码结构如下:
在这里插入图片描述
各功能类解释:
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;
    }

    /**
     * 处理正常批量插入逻辑
     * <p>
     * org.apache.ibatis.session.defaults.DefaultSqlSession$StrictMap 该类方法
     * wrapCollection 实现 StrictMap 封装逻辑
     * </p>
     *
     * @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;

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
读写wav文件需要使用Python中的wave模块,以下是一个读取wav文件并打印一些信息的示例代码: ```python import wave # 打开wav文件 with wave.open('example.wav', 'rb') as wav_file: # 获取文件的基本信息 num_channels = wav_file.getnchannels() sample_width = wav_file.getsampwidth() frame_rate = wav_file.getframerate() num_frames = wav_file.getnframes() # 读取所有数据 data = wav_file.readframes(num_frames) ``` 上面的代码中,`wave.open`函数用于打开wav文件,第一个参数是文件名,第二个参数是打开文件的模式,`'rb'`表示以二进制只读模式打开文件。使用`getnchannels`、`getsampwidth`、`getframerate`和`getnframes`方法可以获取文件的基本信息,分别表示声道数、样本宽度、采样率和帧数。最后使用`readframes`方法读取所有数据。 如果要写入wav文件,可以使用以下代码: ```python import wave # 创建一个新的wav文件 with wave.open('example.wav', 'wb') as wav_file: # 设置文件的基本信息 num_channels = 1 sample_width = 2 frame_rate = 44100 num_frames = 44100 # 设置文件的参数 wav_file.setnchannels(num_channels) wav_file.setsampwidth(sample_width) wav_file.setframerate(frame_rate) wav_file.setnframes(num_frames) # 写入数据 data = b'\x00\x01\x02\x03' * num_frames wav_file.writeframes(data) ``` 上面的代码中,`wave.open`函数的第二个参数改为`'wb'`,表示以二进制写模式打开文件。使用`setnchannels`、`setsampwidth`、`setframerate`和`setnframes`方法设置文件的基本信息。最后使用`writeframes`方法写入数据。注意,写入数据的格式必须与文件的基本信息匹配。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值