Springboot+dynamic-datasource+Druid数据库配置加密

Springboot+mybatis-plus+dynamic-datasource+Druid数据库配置加密

文章目录

  • 0.前言
  • 1. 动态添加移除数据源
  • 2.基础介绍
  • 3. 使用步骤示例
    • 简单方式,使用默认的加密
      • 1. 使用下面 工具类输出,加密后的密码
      • 1. 将上面加密后的密码配置到配置文件中
        • 如果使用的默认key,即上面生成加密后密码的第一种,则使用下面方式配置
        • 如果使用的自定义的key,即上面既生成publicKey和privateKey 以及加密后密码的第2种方式,则使用下面方式配置
  • 4. 官方源码分析
    • 5.1. 解密的核心源码
    • 5.2. 自定义解密
  • 5. 参考资料

0.前言

背景
生产环境中, 为了保密,我们希望将数据库密码加密, 甚至用户名和jdbc连接串加密。本章我们使用由苞米豆(baomidou)团队开发的dynamic-datasource多数据源组件自带的加密工具实现数据库配置加密
在这里插入图片描述

1. 动态添加移除数据源

dynamic-datasource-starter官方给的特性说明中,我们可以看到 dynamic-datasource-starter 支持数据库敏感配置信息 加密(可自定义) ENC()。,所以我们撸一下源码看看到底怎么实现的。
经过查看源码发现, 该框架使用自带的加密工具类com.baomidou.dynamic.datasource.toolkit.CryptoUtils进行加解密, 且自带有公钥私钥。但是源码咋看都觉得眼熟,而且注释是@author alibaba,翻看druid 的加密方法 com.alibaba.druid.filter.config.ConfigTools 。原来作者直接借鉴了Druid加密方法,之前看druid 的加密的时候发现公钥和私钥的使用反了,wenshao给的解释是历史原因。历史背景和源码咱们就聊到这,所以直接使用此工具类加密我们的明文密码, 然后用ENC()包裹即可实现加解密
在这里插入图片描述

2.基础介绍

在使用 Spring Boot、MyBatis-Plus、 Druid 进行数据库配置时,如果需要对敏感配置信息进行加密,可以通过以下方式实现:

  1. 使用加密算法对敏感信息进行加密,如数据库的用户名、密码等信息。可以选择对称加密算法(如AES)或非对称加密算法(如RSA)进行加密。
  2. 将加密后的敏感信息保存在安全的位置,如配置文件或系统环境变量。
  3. 在应用启动时,通过配置文件或环境变量读取加密后的敏感信息。
  4. 在配置动态数据源时,使用解密的敏感信息进行数据库配置。

这是基本的思路,本章我们不造轮子,直接使用国产优秀框架baomidou团队的工具 dynamic-datasource多数据源组件自带的加密工具实现数据库配置加密

3. 使用步骤示例

简单方式,使用默认的加密

1. 使用下面 工具类输出,加密后的密码

import com.baomidou.dynamic.datasource.toolkit.CryptoUtils;
public class DBCryptoUtils extends CryptoUtils{// 第一种方式 使用默认key 加密解密public static void test1( ) throws Exception {System.out.println("-------------------------------------默认加密-------------------------------------");String password = "abc123";String encodePassword = CryptoUtils.encrypt(password);System.out.println("加密后密码:"+CryptoUtils.encrypt(password));}// 第二种方式 使用自定义key,强烈建议public static void test2( ) throws Exception {System.out.println("-------------------------------------自定义key-------------------------------------");String[] pair = CryptoUtils.genKeyPair(512);System.out.println("privateKey:  " + pair[0]);System.out.println("publicKey:  " + pair[1]);// 按道理应该用公钥加密,私钥解密,作者直接抄的druid 的,把这个不规范的写法也给抄过来了,不影响效果,只觉得怪怪的。System.out.println("加密后密码:  " + CryptoUtils.encrypt(pair[0], "abc123"));}public static void main(String[] args) throws Exception {test1();test2();}
}

在这里插入图片描述

1. 将上面加密后的密码配置到配置文件中

如果使用的默认key,即上面生成加密后密码的第一种,则使用下面方式配置

spring:datasource:dynamic:#有默认值可以不配置,强烈建议更换public-key: datasource:master:url: DB地址username: 用户名#配置加密后的密码password: ENC(Ue9QTmtvOX8XMdRIZVqUAbmbLNfAjQQO9jokfVEfaew+HFGZPndSmcq2pOTS2xuC7Pg/z1gUGS82HOmWw0d9Cw==)  driver-class-name: com.mysql.jdbc.Driver# 驱动保持jdbc url一致public-key: #在多数据源下每个数据源可以独立设置,没有就继承上面的。

如果使用的自定义的key,即上面既生成publicKey和privateKey 以及加密后密码的第2种方式,则使用下面方式配置

spring:datasource:dynamic:# 配置上面输出的 public keypublic-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJirfs9pc4fsDdXqjMto4zY+sYZ7d/XYwIQIYqj2FoqxvVC61tjKtG12nMSlwgXbV+DNpWh9W76QjM2XCNYB6VUCAwEAAQ==datasource:master:url: DB地址username: 用户名#配置加密后的密码 根据上面生成的秘钥,加密后的密码password: ENC(BSbigK5YuTXLOUDekSm3uU+h/n2/rIwa4DxQWPbfuhf9irwoakQy777AYHqJVz/WEG5BTFp4Ym+lguH3o+f4kQ==)  driver-class-name: com.mysql.jdbc.Driver# 驱动保持jdbc url一致public-key: #在多数据源下每个数据源可以独立设置,没有就继承上面的。

到这儿基本上就OK了,如果想知道源码是怎么执行的可以继续向下看

4. 官方源码分析

5.1. 解密的核心源码

我们先来看EncDataSourceInitEvent 源码.我们可以看到EncDataSourceInitEvent类,实现了DataSourceInitEvent接口。该类用于在数据源初始化之前对数据源属性进行解密操作。

/*** 多数据源默认解密事件** @author TaoYu*/
@Slf4j
public class EncDataSourceInitEvent implements DataSourceInitEvent {/*** 加密正则*/private static final Pattern ENC_PATTERN = Pattern.compile("^ENC\\((.*)\\)$");@Overridepublic void beforeCreate(DataSourceProperty dataSourceProperty) {String publicKey = dataSourceProperty.getPublicKey();if (StringUtils.hasText(publicKey)) {dataSourceProperty.setUrl(decrypt(publicKey, dataSourceProperty.getUrl()));dataSourceProperty.setUsername(decrypt(publicKey, dataSourceProperty.getUsername()));dataSourceProperty.setPassword(decrypt(publicKey, dataSourceProperty.getPassword()));}}@Overridepublic void afterCreate(DataSource dataSource) {}/*** 字符串解密*/private String decrypt(String publicKey, String cipherText) {if (StringUtils.hasText(cipherText)) {Matcher matcher = ENC_PATTERN.matcher(cipherText);if (matcher.find()) {try {return CryptoUtils.decrypt(publicKey, matcher.group(1));} catch (Exception e) {log.error("DynamicDataSourceProperties.decrypt error ", e);}}}return cipherText;}
}

DataSourceInitEvent 接口 又是干什么用的呢,我们点进去可以看到
在这里插入图片描述

DataSourceInitEvent是 baomidou的dynamic.datasource组件 位于com.baomidou.dynamic.datasource.event包下定义的一个钩子接口,在创建连接池前和后可以搞事情。

  1. 该接口定义了两个方法:beforeCreateafterCreate,用于在连接池创建前后执行一些操作。
  2. beforeCreate方法接受一个DataSourceProperty参数,用于传递数据源的基本信息。
  3. afterCreate方法接受一个DataSource参数,表示已创建的连接池对象。

总之,这段代码是一个事件接口,用于在多数据源连接池创建过程中执行一些自定义操作。
让我们逐行解析代码的功能:

  1. 定义了一个名为ENC_PATTERN的正则表达式模式,用于匹配加密字符串的格式。

  2. 实现了beforeCreate方法,该方法在数据源创建之前调用。它接收一个DataSourceProperty对象作为参数,表示数据源的属性。

  3. beforeCreate方法中,首先获取数据源属性中的公钥(publicKey)。如果公钥存在,表示需要进行解密操作。

  4. 接下来,使用公钥对数据源的URL、用户名和密码进行解密操作。调用decrypt方法对这些属性进行解密,并将解密后的值设置回dataSourceProperty对象中。

  5. 实现了afterCreate方法,该方法在数据源创建之后调用。在该方法中可以执行一些额外的操作,但是该方法在给定的代码中没有实现任何逻辑。

  6. 定义了一个私有方法decrypt,用于对加密字符串进行解密。该方法接收公钥和密文作为参数,并返回解密后的明文字符串。

  7. decrypt方法中,首先判断密文是否符合加密格式(通过ENC_PATTERN进行匹配)。如果匹配成功,就使用给定的公钥和密文调用CryptoUtils.decrypt方法进行解密操作。

总结起来,EncDataSourceInitEvent类实现了DataSourceInitEvent接口,用于在数据源初始化之前对数据源属性进行解密操作。它通过正则表达式匹配加密字符串的格式,并使用给定的公钥对密文进行解密。解密后的明文值将用于设置数据源的URL、用户名和密码属性。

5.2. 自定义解密

到这儿我们可能,已经知道怎么自定义解密,无外乎就是实现DataSourceInitEvent 接口的beforeCreate方法然后自定义处理。但是我们自定义的这个实现类和官方默认的解密实现类优先级怎么搞呢,其实官方在DynamicDataSourceAutoConfiguration配置类中已经使用了@condition条件注解。满足优先使用我们自定义的加密的实现类了。我们只需要交给Spring 容器就OK.
在这里插入图片描述

在这里插入图片描述

/*** 自定义多数据源默认解密事件*/
@Slf4j
@Configuration
public class CustomeEncDataSourceInitEvent implements DataSourceInitEvent {/*** 加密正则 实现自定义的 例如BCC*/private static final Pattern ENC_PATTERN = Pattern.compile("^BCC\\((.*)\\)$");@Overridepublic void beforeCreate(DataSourceProperty dataSourceProperty) {// TODO 实现自定义的解密String publicKey = dataSourceProperty.getPublicKey();if (StringUtils.hasText(publicKey)) {dataSourceProperty.setUrl(decrypt(publicKey, dataSourceProperty.getUrl()));dataSourceProperty.setUsername(decrypt(publicKey, dataSourceProperty.getUsername()));dataSourceProperty.setPassword(decrypt(publicKey, dataSourceProperty.getPassword()));}}@Overridepublic void afterCreate(DataSource dataSource) {}/*** 字符串解密*/private String decrypt(String publicKey, String cipherText) {if (StringUtils.hasText(cipherText)) {Matcher matcher = ENC_PATTERN.matcher(cipherText);if (matcher.find()) {try {return CryptoUtils.decrypt(publicKey, matcher.group(1));} catch (Exception e) {log.error("DynamicDataSourceProperties.decrypt error ", e);}}}return cipherText;}
}

5. 参考资料

  1. dynamic-datasource GitHub 仓库 ↗:dynamic-datasource 的官方 GitHub 仓库,包含源代码、文档和示例等资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/103388.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[golang gin框架] 43.Gin商城项目-微服务实战之后台Rbac微服务之管理员的增删改查以及管理员和角色关联

上一节讲解了后台Rbac微服务角色增删改查微服务,这里讲解权限管理Rbac微服务管理员的增删改查微服务以及管理员和角色关联微服务功能 一.实现后台权限管理Rbac之管理员增删改查微服务服务端功能 1.创建Manager模型 要实现管理员的增删改查,就需要创建对应的模型,故在server/r…

AMBA总线协议(9)——AHB(七):终章

一、前言 在之前的文章中我们讲述了AHB协议的分割传输机制,它使得从机可以决定一次传输是否继续进行,以防止 传输的执行将占据大量的时钟周期,有效提高了总线的公平性与效率问题,本文中我们将一次性学习完AHB最后的内容&#xff0…

一文速学-让神经网络不再神秘,一天速学神经网络基础(一)

前言 思索了很久到底要不要出深度学习内容,毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新,很多坑都没有填满,而且现在深度学习的文章和学习课程都十分的多,我考虑了很久决定还是得出神经网络系列文章,…

docker: /lib64/libc.so.6: version `GLIBC_2.32‘ not found (required by docker)

Linux环境 Ubuntu 22.04 docker 最新版 jenkins docker 版本(以下版本都会报错 jenkins/jenkins:centos7 jenkins/jenkins:lts-centos7 jenkins/jenkins:ltsdocker-compose.yml配置 version: 3.6 services:gitlab:image: twang2218/gitlab-ce-zhrestart: alwayscontainer_nam…

港联证券|股票风险大吗?股票亏了怎么办?

在股市波动剧烈的时分,很多人会忧虑本身投资是否安全,是否能够获得理想的收益。那么股票危险大吗?股票亏了怎么办?我们准备了相关内容,以供参考。 股票危险大吗? 股票危险大不大并没有一个肯定的答案&…

微服务中间件--多级缓存

多级缓存 多级缓存a.JVM进程缓存1) Caffeine2) 案例 b.Lua语法1) 变量和循环2) 条件控制、函数 c.多级缓存1) 安装OpenResty2) 请求参数处理3) 查询Tomcat4) Redis缓存预热5) 查询Redis缓存6) Nginx本地缓存 d.缓存同步1) 数据同步策略2) 安装Canal2.a) 开启MySQL主从2.b) 安装…

前端vscode必备插件(强烈推荐)

目录 一、前言 二、工具推荐 1.《Chinese (Simplified) (简体中文) Language》 2.《ESLint》 3.《Git History》 4.vscode-icons 5.Path Intellisense 6.《Vetur》 7.《GitLens — Git supercharged》 8.《Image preview》 9.Debugger for Chrome 10.Prettier 11…

微服务中间件--Ribbon负载均衡

Ribbon负载均衡 a.Ribbon负载均衡原理b.Ribbon负载均衡策略 (IRule)c.Ribbon的饥饿加载 a.Ribbon负载均衡原理 1.发起请求http://userservice/user/1,Ribbon拦截该请求 2.Ribbon通过EurekaServer拉取userservice 3.EurekaServer返回服务列表给Ribbon做负载均衡 …

【云驻共创】华为云之手把手教你搭建IoT物联网应用充电桩实时监控大屏

文章目录 前言1.什么是充电桩2.什么是IOT3.什么是端、边、云、应用协同4.什么是Astro轻应用 一、玩转lOT动态实时大屏(线下实际操作)1.Astro轻应用说明1.1 场景说明1.2 资费说明1.3 整体流程 2.操作步骤2.1 开通设备接入服务2.2 创建产品2.3 注册设备2.4…

上海交大ACM班总教头团队重磅新作,带你动手学机器学习(文末赠书4本)

目录 0 写在前面1 什么是机器学习?2 ACM 班总教头:俞勇3 动手学习机器学习赠书活动 0 写在前面 机器学习强基计划聚焦深度和广度,加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理;“广”在分析多个机器…

stm32之5.长按按键(使用时钟源)调整跑马灯速度

------------------------------ 源码 #include <stm32f4xx.h> #include "led.h" #include "delay.h" #include "my_str.h" #include "beep.h" #include "key.h" int main(void) { key_init(); Led_init();…

redis高级----------主从复制

redis的四种模式&#xff1a;单例模式&#xff1b;主从模式&#xff1b;哨兵模式&#xff0c;集群模式 一、主从模式 单例模式虽然操作简单&#xff0c;但是不具备高可用 缺点&#xff1a; 单点的宕机引来的服务的灾难、数据丢失单点服务器内存瓶颈&#xff0c;无法无限纵向扩…

7-42 整型关键字的散列映射

题目链接&#xff1a;这里 题目大意&#xff1a;就是写一个线性探测的散列 然鹅&#xff0c;我不会写(?)我一共错了两个地方 有冲突的情况下&#xff0c;就是线性探查然后往后找&#xff0c;但是我之前写的是t&#xff0c;应该是t (t1)%p;…在有重复关键字的时候&#xff0c…

运行flutter doctor命令窗口直接闪退

在cmd中输入flutter doctor后闪退了。 使用高速摄像机可以看到报错信息。 报错信息的意思是git的文件夹不能删掉&#xff0c;请保留flutter中git文件。

数据结构——栈和队列OJ题

栈和队列小提升&#xff01; 前言一、用队列实现栈队列接口实现&#xff08;1&#xff09;栈的接口定义&#xff08;2&#xff09;栈的初始化&#xff08;3&#xff09;入栈函数的定义&#xff08;4&#xff09;出栈函数的定义&#xff08;5&#xff09;查找栈顶元素&#xff0…

vue3 计算两个表单得到第三个表单数据

<el-formref"ruleFormRef"label-width"150px"label-suffix":":rules"rules":disabled"drawerProps.isView":model"drawerProps.rowData"><el-form-item label"云平台名称" prop"cloudId&…

硬件知识积累 LED的介绍与选型 (简单电路)

1. LED 的介绍 1.1 LED 是什么 LED :是一种能发光的半导体电子元件。发光二极管&#xff08;LED&#xff09;于20世纪60年代问世。在20世纪80年代之前&#xff0c;LED主要作为指示灯使用&#xff0c;从其光色来看&#xff0c;只有红光、橙光、黄光和绿光等几种。这一时期属于…

游乐场vr设备虚拟游乐园vr项目沉浸体验馆

在景区建设一个VR游乐场项目可以为游客提供一种新颖、刺激和沉浸式的游乐体验。提高游客的体验类型&#xff0c;以及景区的类目&#xff0c;从而可以吸引更多的人来体验。 1、市场调研&#xff1a;在决定建设VR游乐场项目之前&#xff0c;需要进行市场调研&#xff0c;了解当地…

基于Spark+django的国漫推荐系统--计算机毕业设计项目

近年来&#xff0c;随着互联网的蓬勃发展&#xff0c;企事业单位对信息的管理提出了更高的要求。以传统的管理方式已无法满足现代人们的需求。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;随着各行业的不断发展&#xff0c;基…