热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

多数据源模式JPA整合shardingjdbc实现数据脱敏

这篇文章主要为大家介绍了JPA项目中多数据源模式整合sharding-jdbc来实现数据脱敏,有需要的朋友可以借鉴参考下,希望能够有所

多数据源模式JPA整合sharding-jdbc实现数据脱敏

前言

前一篇博文,已经完整的介绍了数据库脱敏的场景以及方案,来自京东数科的Sharding-JDBC开源项目通过对数据源中间代理的方式透明化的实现了这个功能,但是,功能虽然实现了,sql兼容的小问题还是很多,比如目前还不支持子查询,数据库定义的关键字不允许使用,等等问题,反观我们需要加解密的字段,其实占比非常小,即使遇到了和组件不兼容的地方也可以稍加改动解决掉,所以最后博主给出了一个比较完善的组件集成方案:多数据源模式,需要加解密的数据源和业务其他数据源隔离。

既解决了数据库字段加解密的额问题,同时也解决了组件对sql的兼容问题。

下面是具体的集成步骤以及需要注意的点

引入依赖

            
                org.apache.shardingsphere
                sharding-jdbc-spring-boot-starter
                ${sharding.jdbc.version}
            

这里需要说明下,虽然采用多数据源兼容后,不能使用组件基于spring boot自动装配功能了,但是这里还是建议导入sharding-spring-boot-starter包,因为这个包下内置了配置映射的类,在自定义数据源的时候非常有用

添加sharding数据源配置

#数据库源配置
spring.shardingsphere.datasource.name = ds
spring.shardingsphere.datasource.ds.type = com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.jdbc-url = jdbc:mysql://xxx?autoRecOnnect=true&useUnicode=true&characterEncoding=utf-8
spring.shardingsphere.datasource.ds.username = root
spring.shardingsphere.datasource.ds.password = xxx
spring.shardingsphere.encrypt.encryptors.encryptor_aes.type = aes
spring.shardingsphere.encrypt.encryptors.encryptor_aes.props.aes.key.value = 123456
spring.shardingsphere.encrypt.tables.account.columns.password.plainColumn = password
spring.shardingsphere.encrypt.tables.account.columns.password.cipherColumn = password_encrypt
spring.shardingsphere.encrypt.tables.account.columns.password.encryptor = encryptor_aes
spring.shardingsphere.props.sql.show = true
spring.shardingsphere.props.query.with.cipher.column = true

排除自动装配

@SpringBootApplication(exclude = SpringBootConfiguration.class)

由于导入了starter包,所以这里需要手动排除自动装载类,

业务数据源配置

多数据源后,业务本身的数据源也需要手动配置,默认的spring boot jpa自动转载类会判断上线文中是否存在EntityManagerFactory类,如果有就不会初始化了,所以两个数据源都需要手动配置

@Configuration
@EnableConfigurationProperties(JpaProperties.class)
public class DataSourceConfiguration{
    private final JpaProperties jpaProperties;
    private final Environment environment;

    public DataSourceConfiguration(JpaProperties jpaProperties, Environment environment) {
        this.jpaProperties = jpaProperties;
        this.envirOnment= environment;
    }
    @Primary
    @Bean
    public DataSource dataSource(){
        String prefix = "spring.shardingsphere.datasource.";
        String each = getDataSourceNames(prefix).get(0);
        try {
            return  getDataSource(prefix, each);
        } catch (final ReflectiveOperationException ex) {
            throw new ShardingSphereException("Can"t find datasource type!", ex);
        }
    }
    @Primary
    @Bean
    public EntityManagerFactory entityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabase(Database.MYSQL);
        vendorAdapter.setGenerateDdl(true);
        vendorAdapter.setShowSql(true);
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPersistenceUnitName("default");
        factory.setPackagesToScan(Constants.BASE_PACKAGES);
        factory.setDataSource(dataSource());
        factory.setJpaPropertyMap(jpaProperties.getProperties());
        factory.afterPropertiesSet();
        return factory.getObject();
    }
    @Bean
    @Primary
    public EntityManager entityManager(EntityManagerFactory entityManagerFactory){
        return SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory);
    }
    @Primary
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory){
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }
    private ListgetDataSourceNames(final String prefix) {
        StandardEnvironment standardEnv = (StandardEnvironment) environment;
        standardEnv.setIgnoreUnresolvableNestedPlaceholders(true);
        return null == standardEnv.getProperty(prefix + "name")
                ? new InlineExpressionParser(standardEnv.getProperty(prefix + "names")).splitAndEvaluate() : Collections.singletonList(standardEnv.getProperty(prefix + "name"));
    }
    @SuppressWarnings("unchecked")
    private DataSource getDataSource(final String prefix, final String dataSourceName) throws ReflectiveOperationException {
        Map dataSourceProps = PropertyUtil.handle(environment, prefix + dataSourceName.trim(), Map.class);
        Preconditions.checkState(!dataSourceProps.isEmpty(), "Wrong datasource properties!");
        DataSource result = DataSourceUtil.getDataSource(dataSourceProps.get("type").toString(), dataSourceProps);
        DataSourcePropertiesSetterHolder.getDataSourcePropertiesSetterByType(dataSourceProps.get("type").toString()).ifPresent(
                dataSourcePropertiesSetter -> dataSourcePropertiesSetter.propertiesSet(environment, prefix, dataSourceName, result));
        return result;
    }
}

上面代码需要注意三个地方

一是数据源的配置,是以sharding的配置来解析获得的,是因为我们已经集成过了,不想改动配置,所以如此,如果还没集成过,可以直接使用spring 配置数据源的方式配置即可。

二是EntityManager的初始化,通过SharedEntityManagerCreator包装了下,是因为我们业务的查询通过继承SimpleJpaRepository来扩展功能的,通过SharedEntityManagerCreator包装保留了完整的事务功能。

三是需要给所有的业务数据源的配置添加 @Primary注解,让sprign上下文默认使用业务数据源

加解密数据源配置

/**
 * @author: kl @kailing.pub
 * @date: 2020/5/18
 */
@Configuration
@EnableConfigurationProperties({JpaProperties.class,SpringBootEncryptRuleConfigurationProperties.class, SpringBootPropertiesConfigurationProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, DataSourceConfiguration.class})
public class EncryptDataSourceConfiguration {
    private final SpringBootPropertiesConfigurationProperties props;
    private final SpringBootEncryptRuleConfigurationProperties encryptRule;
    private final JpaProperties jpaProperties;
    private final DataSource dataSource;
    public EncryptDataSourceConfiguration(SpringBootPropertiesConfigurationProperties props, SpringBootEncryptRuleConfigurationProperties encryptRule, JpaProperties jpaProperties, DataSource dataSource) {
        this.props = props;
        this.encryptRule = encryptRule;
        this.jpaProperties = jpaProperties;
        this.dataSource = dataSource;
    }
    @Bean
    public DataSource encryptDataSource() throws SQLException {
        return EncryptDataSourceFactory.createDataSource(dataSource, new EncryptRuleConfigurationYamlSwapper().swap(encryptRule), props.getProps());
    }
    @Bean
    public EntityManagerFactory encryptEntityManagerFactory() throws SQLException {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabase(Database.MYSQL);
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPersistenceUnitName("encryptPersistenceUnit");
        factory.setPackagesToScan(Constants.BASE_PACKAGES);
        factory.setDataSource(encryptDataSource());
        factory.setJpaPropertyMap(jpaProperties.getProperties());
        factory.afterPropertiesSet();
        return factory.getObject();
    }
    @Bean
    public EntityManager encryptEntityManager() throws SQLException {
        return SharedEntityManagerCreator.createSharedEntityManager(encryptEntityManagerFactory());
    }
    @Bean
    public PlatformTransactionManager encryptTransactionManager() throws SQLException {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(encryptEntityManagerFactory());
        return txManager;
    }
}

加解密数据源的源来自于业务数据源,只是在这里给业务数据源又代理了一层加解密的逻辑。加解密的规则配置采用了sharding-spring-boot-starter包中的映射类,所以可以保留和spring boot配置方式一致。

加解密数据源的使用

在使用时,因为默认使用的是业务数据源,所以需要在需要加解密的地方通过@Qualifier("encryptEntityManager")显示的注入加解密的数据源代理,如:

@Repository
public class AccountRepository extends AbstractJpaRepository {

    public AccountRepository(@Qualifier("encryptEntityManager") EntityManager em) {
        super(AccountModel.class, em);
    }
    @Override
    @Transactional(transactiOnManager= "encryptTransactionManager")
    public  S save(S entity) {
        return super.save(entity);
    }
}

另,需要手动指定加解密数据源的事务管理器

结语

没有十全十美的组件,Sharding-JDBC的数据脱敏方案已经趋向于完美了。由于组件本身的架构设计,确实不好做到100%的兼容。在发现加解密组件不支持子查询时,博主发现实现这个功能很简单,尝试过向官方添加这个功能提交pr。经过对组件的进一步了解发现,从全局考虑实现这个功能非常复杂,也就放弃了。目前这个多数据源模式可以很好的解决这个问题,如果有更好的集成方案,欢迎在下面留言交流

以上就是多数据源模式JPA整合sharding-jdbc实现数据脱敏的详细内容,更多关于多数据源JPA整合sharding-jdbc数据脱敏的资料请关注编程笔记其它相关文章!


推荐阅读
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 我猜想开发中大多都用注解,因为简单吗,哈哈正题:注解:就是一个类,使用注解名称。开发中:使用注解 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • springboot基于redis配置session共享项目环境配置pom.xml引入依赖application.properties配置Cookie序列化(高版本不需要)测试启 ... [详细]
  • Ribbon使用Hystrix
    1、导入依赖spring-cloud-starter-hystrixorg.springframework.cloud ... [详细]
  • @Repository和@Controller、@Service、@Component的作用差不多,都是把对象交给spring管理。@Repository用在持久层的接口上,这个注解是将接口的 ... [详细]
author-avatar
mobiledu2502878137
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有