拦截Druid数据源自动注入帐密解密实现详解

目录
  • 背景
    • 加密数据源自主实现流程
    • 基础巩固
    • 额外尝试
    • 启示录

背景

SpringBoot 项目,使用 Druid 自动装配的数据源,数据源的帐号密码配置加密后,如何完成数据源的装配呢?

druid-spring-boot-starter 虽然自带了加密配置,但是密钥也是配置的,如果需要用自定义的加密解密工具,如果不用自带的工具,怎么自定义实现加密数据源的装配呢?

本文从 DruidDataSourceAutoConfigure 类源码入手,仿造该类,自定义一个数据源注入配置,在真正注入 DruidDataSource 之前,对 druid 配置信息完成解密。

主要思考三个问题:

  • 自定的 Configuration 类中的 @Bean 注入一个 DruidDataSource ,为什么比自动装配的时机早呢?
  • 如果自定义一个自动装配类, 包含DataSourceProperties 属性,对它的帐号密码解密后,让它在DruidDataSourceAutoConfigure 类之前装配,怎么实现呢?
  • 自动装配类的工作原理是什么?注入优先级怎么确定的?

加密数据源自主实现流程

Not registered via @EnableConfigurationProperties,
marked as Spring component,
or scanned via @ConfigurationPropertiesScan

@ConfigurationProperties 用法限制,我想到一个解决办法,为当前类加上 @Component,同时制定一个不可能的注入条件:@ConditionalOnProperty(prefix = "xx",name = "xxx", havingValue = "impossible")

不用官方的加密插件,自定义 Druid 的解密配置,我想到的方法是完全仿照 Druid 数据源的自动装配过程,改写 DruidDataSource 的注入过程。

关键是修改 DataSourceProperties 这个类的实例的帐号密码属性,其他完全照搬 DruidDataSourceAutoConfigure 实现即可。

第一步,由于 Druid 自动注入的数据源 DruidDataSourceWrapper 是一个包内类,不能直接拿来用,所以完全拷贝一份这个类,定义为咱们自己的数据源类:

@Component
@ConfigurationProperties("spring.datasource.druid")
@ConditionalOnProperty(prefix = "spring.datasource",name = "encrypted", havingValue = "impossible")
public class MyEncryptedDatasourceWrapper extends DruidDataSource implements InitializingBean {
    @Autowired
    private DataSourceProperties basicProperties;
    public MyEncryptedDatasourceWrapper() {
    }
    @Override
    public void afterPropertiesSet() {
        if (super.getUsername() == null) {
            super.setUsername(this.basicProperties.determineUsername());
        }
        if (super.getPassword() == null) {
            super.setPassword(this.basicProperties.determinePassword());
        }
        if (super.getUrl() == null) {
            super.setUrl(this.basicProperties.determineUrl());
        }
        if (super.getDriverClassName() == null) {
            super.setDriverClassName(this.basicProperties.getDriverClassName());
        }
    }
    @Autowired(
            required = false
    )
    public void autoAddFilters(List<Filter> filters) {
        super.filters.addAll(filters);
    }
    @Override
    public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
        try {
            super.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
        } catch (IllegalArgumentException var4) {
            super.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
        }
    }
}

第二步,自定义一个 DruidDataSourceAutoConfigure 类,内容与该类一样,但是多一个数据源配置属性:

@Configuration
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class})
public class MyEncryptedDatasourceWrapperConfig {
    /**
     * 该属性封装了 spring.datasource 属性,需要对它的帐号、密码属性进行解密
     */
    @Autowired
    private DataSourceProperties basicProperties;
    /**
     * 使用数据源配置信息,解密帐号和密码后创建数据库连接池
     * @return
     */
    @Bean
    public DataSource dataSource() {
        // TODO 对密码解密并设置回去
        basicProperties.setPassword(password);
        return new MyEncryptedDatasourceWrapper();
    }
}

这样就完成了 Spring druid 数据源配置的解密处理了。

基础巩固

boolean proxyBeanMethods() 默认值是 true. 从这个成员变量的注释中,我们可以看到一句话 Specify whether {@code @Bean} methods should get proxied in order to enforce bean lifecycle behavior, e.g. to return shared singleton bean instances even in case of direct {@code @Bean} method calls in user code.

其实从这句话,我们就可以初步得到我们想要的答案了:在带有 @Configuration 注解的类中,一个带有 @Bean 注解的方法显式调用另一个带有 @Bean 注解的方法,返回的是共享的单例对象。

参考文档:《Component 和 Configuration 区别》

额外尝试

加密数据源配置的解密流程,核心在 DataSourceProperties 这个实例装配完成后修改密码信息,尝试自定义一个 @Configuration@Bean 注入一个 DataSourceProperties 实例,但是这个对象到了 Druid 自动注入类那里,属性还是没有发生变化:

@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class MyAutoConfig {
    @Autowired
    private DataSourceProperties basicProperties;
    public MyAutoConfig() {
        System.out.println("My Auto config");
    }
    @Bean
    public DataSourceProperties basicProperties() {
        // TODO 解密配置
        System.out.println("username " + basicProperties.getUsername());
        return basicProperties;
    }
}

这里 @Bean 注入生效了,到了 DruidDataSource 那使用的也是这个实例,单步调试对象地址是一样的,但是改的属性没有生效。

数据源实例化配置时引用的属性:

但是两个地方的属性却不同,前一步解密的信息并没有传递到真正使用的地方。 理论上,同一个对象,前面修改了属性,这里同一个线程里面,属性应该变化了才对呢!不得其解。

启示录

回顾开头的三个问题:

  • 自定的 Configuration 类中的 @Bean 注入一个 DruidDataSource ,为什么比自动装配的时机早呢?因为 @Bean 属于当前项目扫描路径,它里面的类注入优先级高于第三方 jar 包中的 spring.factories 的装配类。
  • 如果自定义一个自动装配类, 包含DataSourceProperties 属性,对它的帐号密码解密后,让它在DruidDataSourceAutoConfigure 类之前装配,怎么实现呢?尝试定义一个装配类 @Bean 装配一个数据源 DataSourceProperties 对象,并修改配置。
  • 自动装配类的工作原理是什么?注入优先级怎么确定的?spring.factories 的本质是 SPI,它针对的是第三方 jar 包,不需要手动配置扫描路径,又需要自动注入的情况,是各种 starter 定义底层实现途径。

优先级:本地扫描路径的 Configuration -> 实现了 BeanDefinitionRegistryPostProcessor 接口的类 -> spring.factories 中的自动装配类。

以上就是拦截Druid数据源自动注入帐密解密实现详解的详细内容,更多关于Druid注入帐密解密拦截的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot整合阿里 Druid 数据源的实例详解

    目录 1. 在容器中注册 DruidDataSource 数据源. 2. Druid 数据源各种属性配置方法 3. 开启Druid的内置监控页面 4. 打开 Druid 监控统计功能 5. 配置Web和Spring关联监控 6. 配置防火墙: 7. 给监控页加入账号密码 前言:今年是我的第二个 1024 了 ,和我一起大声说出来,技术宅改变世界!!! 本节主要介绍的是:SpringBoot 整合阿里 Druid 数据源手动配置方法 1. 在容器中注册 DruidDataSource 数据源. 编

  • Druid之连接创建及销毁示例详解

    目录 前言 正文 一. DruidDataSource连接创建 二. DruidDataSource连接销毁 总结 前言 Druid是阿里开源的数据库连接池,是阿里监控系统Dragoon的副产品,提供了强大的可监控性和基于Filter-Chain的可扩展性. 本篇文章将对Druid数据库连接池的连接创建和销毁进行分析.分析Druid数据库连接池的源码前,需要明确几个概念. Druid数据库连接池中可用的连接存放在一个数组connections中: Druid数据库连接池做并发控制,主要靠一把可重

  • 数据库连接池Druid与Hikari对比详解

    目录 Druid竞品对比 Hikari 官方性能测试数据 对比 总结 Druid竞品对比 功能类别 功能 Druid HikariCP DBCP Tomcat-jdbc C3P0 性能 PSCache 是 否 是 是 是 LRU 是 否 是 是 是 SLB负载均衡支持 是 否 否 否 否 稳定性 ExceptionSorter 是 否 否 否 否 扩展 扩展 Filter JdbcIntercepter 监控 监控方式 jmx/log/http jmx/metrics jmx jmx jmx 支

  • Java Druid连接池与Apache的DBUtils使用教程

    目录 Druid连接池 连接池思想 Druid连接池使用步骤 引入相关jar包 创建database.properties配置文件 编写连接池工具类 Druid连接池测试 Apache的DBUtils使用 Apache DBUtils介绍 Apache DBUtils特征 Apache DbUtils主要组成 Apache DbUtils使用步骤 综合案例 创建product表 向表中添加数据 创建实体类Product 创建ProductDao接口 创建ProductDaoImpl实现类 创建P

  • 解决springboot druid数据库连接池连接失败后一直重连问题

    目录 druid数据库连接池连接失败后一直重连问题 druid数据库连接池技术的实现与常见错误 第一步,win+R cmd进入到doc窗口,敲入mysql -V 第二步,写好配置文件jdbc.properties 总结 druid数据库连接池连接失败后一直重连问题 当数据库暂停或者拒绝连接时,druid会一直连接 增加如下配置可以解决重连问题 spring.datasource.druid.break-after-acquire-failure=true spring.datasource.dr

  • SpringBoot整合Mybatis与druid实现流程详解

    目录 SpringBoot整合junit SpringBoot整合junit SpringBoot整合junit的classes SpringBoot整合Mybatis 整合前的准备 整合Mybatis SpringBoot 整合druid 配置前置知识小点 整合druid SpringBoot整合junit SpringBoot整合junit ①还是一样,我们首先创建一个SpringBoot模块. 由于我们并不测试前端,而只是整合junit,所以不用选择模板,选择其中的web即可. 完成以后我

  • Spring拦截器中注入Bean失败解放方案详解

    目录 简介 问题重现 解决方案 简介 说明 本文用示例介绍如何解决拦截器中注入Bean失败的问题. 场景 Token拦截器中需要用@Autowired注入JavaJwtUtil类,结果发现注入的JavaJwtUtil为Null. 原因 拦截器的配置类是以new JwtInterceptor的方式使用的,那么这个JwtInterceptor不受Spring管理.因此,里边@Autowired注入JavaJwtUtil是不会注入进去的. 问题重现 代码 application.yml server:

  • springboot多数据源配置及切换的示例代码详解

    注:本文的多数据源配置及切换的实现方法是,在框架中封装,具体项目中配置及使用,也适用于多模块项目 配置文件数据源读取 通过springboot的Envioment和Binder对象进行读取,无需手动声明DataSource的Bean yml数据源配置格式如下: spring: datasource: master: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url:

  • 在C#程序中注入恶意DLL的方法详解

    目录 一.背景 二.实现原理 1. 基本思路 2. 案例演示 3. 自定义注入 三:总结 一.背景 前段时间在训练营上课的时候就有朋友提到一个问题,为什么 Windbg 附加到 C# 程序后,程序就处于中断状态了?它到底是如何实现的?其实简而言之就是线程的远程注入,这一篇就展开说一下. 二.实现原理 1. 基本思路 WinDbg 在附加进程的时候,会注入一个线程到 C# 进程 中,注入成功后,会执行一个 DbgBreakPoint() 函数,其实就是 int 3 ,这时候 CPU 就会执行 3

  • Spring自动装配与扫描注解代码详解

    1 javabean的自动装配 自动注入,减少xml文件的配置信息. <?xml version="1.0" encoding="UTF-8"?> <!-- 到入xml文件的约束 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p&quo

  • Springboot自动配置与@Configuration配置类详解

    目录 @Configuration 注意点1 注意点2 注意点3 注意点4 springboot自动配置 @Configuration 注意点1 配置类(@Configuration下的这个类)其实相当于一个工厂, 标注 @Bean 注解的方法相当于工厂方法 考虑有如下例子: @Configuration // 注意点1: 配置类其实相当于一个工厂, 标注 @Bean 注解的方法相当于工厂方法 static class MyConfig { @Bean public Bean1 bean1()

  • MySQL加密和解密实例详解

    MySQL加密和解密实例详解 数据加密.解密在安全领域非常重要.对程序员而言,在数据库中以密文方式存储用户密码对入侵者剽窃用户隐私意义重大. 有多种前端加密算法可用于数据加密.解密,下面我向您推荐一种简单的数据库级别的数据加密.解密解决方案.以MySQL数据库为例,它内建了相应的加密函数(AES_ENCRYPT() )和解密函数(AES_DECRYPT()). 在建表的时候,要注意字段的类型.如下图所示: 在表中插入加密数据 上面的插入语句有三个字段,"用户名"."密码&qu

  • python下读取公私钥做加解密实例详解

    python下读取公私钥做加解密实例详解 在RSA有一种应用模式是公钥加密,私钥解密(另一种是私钥签名,公钥验签).下面是Python下的应用举例. 假设我有一个公钥文件,rsa_pub.pem, 我要读取这个公钥并用它来加密. from M2Crypto import RSA,BIO fp = file('rsa_pub.pem','rb'); pub_key_str = fp.read(); fp.close(); mb = BIO.MemoryBuffer(pub_key_str); pu

  • 使用ThinkPHP的自动完成实现无限级分类实例详解

    一.实现效果 二.主要代码 1.模板 2.控制器 ·index模块 ·add模块 3.模型 三.代码 以便于各位看官复制测试 1.模板 <form action="__URL__/add" method="post"> 栏目<select name="fid" size=20> <option value="0">栏目</option> <volist name='list

  • 使用PXE自动安装CentOS7.6的教程详解

    一.需求 基地新到300台服务器,需要自实施安装CentOS7.6版本操作系统,选择使用PXE进行批量安装. 二.准备工作 使用二层交换机连接未安装操作系统服务器,避免影响现网正常服务器. 上传操作系统镜像到服务器并安装PXE环境必备服务. 挂载镜像文件作为本地软件仓库. 环境准备 systemctl stop firewalld # 关闭防火墙 setenforce 0 # 临时设置SELINUX为宽松模式 sed -i '/^SELINUX=/s/.*/SELINUX=disabled/'

  • NodeJS加密解密及node-rsa加密解密用法详解

    要用nodejs开发接口,实现远程调用,如果裸奔太危险了,就在网上找了一下nodejs的加密,感觉node-rsa挺不错的,下面来总结一下简单的rsa加密解密用法 初始化环境 新建一个文件夹 node-rsa-demo , 终端进入,运行下面命令初始化 cd node-rsa-demo npm init # 一路回车即可 npm install --save node-rsa 生成公钥私钥 在 node-rsa-demo 下新建一个文件 index.js 写上如下代码 var NodeRSA =

随机推荐